Index: gpu/command_buffer/service/gles2_cmd_decoder.cc |
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc |
index f97710e86a61009ce7b6b54517f63040d5f8cb3b..7257dfa17d1d6f20ed0468db7f79a665b378fdd6 100644 |
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc |
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc |
@@ -167,6 +167,25 @@ static gfx::OverlayTransform GetGFXOverlayTransform(GLenum plane_transform) { |
} |
} |
+static size_t BitsPerPixel(GLenum format) { |
+ switch (format) { |
+ case GL_RGB: |
+ return 24; |
+ case GL_RGBA: |
+ return 32; |
+ case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD: |
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: |
+ return 8; |
+ case GL_ATC_RGB_AMD: |
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: |
+ case GL_ETC1_RGB8_OES: |
+ return 4; |
+ } |
+ |
+ NOTREACHED(); |
+ return 0; |
+} |
+ |
} // namespace |
class GLES2DecoderImpl; |
@@ -944,6 +963,12 @@ class GLES2DecoderImpl : public GLES2Decoder, |
GLenum internal_format, |
GLenum dest_type); |
+ void DoCopyCompressedTextureCHROMIUM(GLenum target, |
+ GLuint source_id, |
+ GLuint target_id, |
+ GLenum internal_format, |
+ GLenum dest_type); |
+ |
// Wrapper for TexStorage2DEXT. |
void DoTexStorage2DEXT( |
GLenum target, |
@@ -1652,6 +1677,18 @@ class GLES2DecoderImpl : public GLES2Decoder, |
GLsizei width, GLsizei height, GLenum format, |
Texture* texture); |
+ bool ValidateCompressedTexSubImage2D(error::Error* error, |
+ const char* function_name, |
+ GLenum target, |
+ GLint level, |
+ GLint xoffset, |
+ GLint yoffset, |
+ GLsizei width, |
+ GLsizei height, |
+ GLenum format, |
+ GLsizei image_size, |
+ const void* data); |
+ |
void RenderWarning(const char* filename, int line, const std::string& msg); |
void PerformanceWarning( |
const char* filename, int line, const std::string& msg); |
@@ -2839,8 +2876,12 @@ Capabilities GLES2DecoderImpl::GetCapabilities() { |
caps.egl_image_external = |
feature_info_->feature_flags().oes_egl_image_external; |
+ caps.texture_format_atc = |
+ feature_info_->feature_flags().ext_texture_format_atc; |
caps.texture_format_bgra8888 = |
feature_info_->feature_flags().ext_texture_format_bgra8888; |
+ caps.texture_format_dxt = |
+ feature_info_->feature_flags().ext_texture_format_dxt; |
caps.texture_format_etc1 = |
feature_info_->feature_flags().oes_compressed_etc1_rgb8_texture; |
caps.texture_format_etc1_npot = |
@@ -8343,70 +8384,18 @@ bool GLES2DecoderImpl::ClearLevel( |
return true; |
} |
-namespace { |
- |
-const int kS3TCBlockWidth = 4; |
-const int kS3TCBlockHeight = 4; |
-const int kS3TCDXT1BlockSize = 8; |
-const int kS3TCDXT3AndDXT5BlockSize = 16; |
- |
-bool IsValidDXTSize(GLint level, GLsizei size) { |
- return (size == 1) || |
- (size == 2) || !(size % kS3TCBlockWidth); |
-} |
- |
-bool IsValidPVRTCSize(GLint level, GLsizei size) { |
- return GLES2Util::IsPOT(size); |
-} |
- |
-} // anonymous namespace. |
- |
bool GLES2DecoderImpl::ValidateCompressedTexFuncData( |
const char* function_name, |
GLsizei width, GLsizei height, GLenum format, size_t size) { |
- unsigned int bytes_required = 0; |
+ int bytes_required = 0; |
- switch (format) { |
- case GL_ATC_RGB_AMD: |
- case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: |
- case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: |
- case GL_ETC1_RGB8_OES: { |
- int num_blocks_across = |
- (width + kS3TCBlockWidth - 1) / kS3TCBlockWidth; |
- int num_blocks_down = |
- (height + kS3TCBlockHeight - 1) / kS3TCBlockHeight; |
- int num_blocks = num_blocks_across * num_blocks_down; |
- bytes_required = num_blocks * kS3TCDXT1BlockSize; |
- break; |
- } |
- case GL_ATC_RGBA_EXPLICIT_ALPHA_AMD: |
- case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD: |
- case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: |
- case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: { |
- int num_blocks_across = |
- (width + kS3TCBlockWidth - 1) / kS3TCBlockWidth; |
- int num_blocks_down = |
- (height + kS3TCBlockHeight - 1) / kS3TCBlockHeight; |
- int num_blocks = num_blocks_across * num_blocks_down; |
- bytes_required = num_blocks * kS3TCDXT3AndDXT5BlockSize; |
- break; |
- } |
- case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG: |
- case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: { |
- bytes_required = (std::max(width, 8) * std::max(height, 8) * 4 + 7)/8; |
- break; |
- } |
- case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG: |
- case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: { |
- bytes_required = (std::max(width, 16) * std::max(height, 8) * 2 + 7)/8; |
- break; |
- } |
- default: |
- LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, format, "format"); |
- return false; |
+ if (!GLES2Util::ComputeCompressedImageSize(width, height, format, |
+ &bytes_required)) { |
+ LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, format, "format"); |
+ return false; |
} |
- if (size != bytes_required) { |
+ if (size != static_cast<size_t>(bytes_required)) { |
LOCAL_SET_GL_ERROR( |
GL_INVALID_VALUE, function_name, "size is not correct for dimensions"); |
return false; |
@@ -8418,47 +8407,13 @@ bool GLES2DecoderImpl::ValidateCompressedTexFuncData( |
bool GLES2DecoderImpl::ValidateCompressedTexDimensions( |
const char* function_name, |
GLint level, GLsizei width, GLsizei height, GLenum format) { |
- switch (format) { |
- case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: |
- case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: |
- case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: |
- case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: { |
- if (!IsValidDXTSize(level, width) || !IsValidDXTSize(level, height)) { |
- LOCAL_SET_GL_ERROR( |
- GL_INVALID_OPERATION, function_name, |
- "width or height invalid for level"); |
- return false; |
- } |
- return true; |
- } |
- case GL_ATC_RGB_AMD: |
- case GL_ATC_RGBA_EXPLICIT_ALPHA_AMD: |
- case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD: |
- case GL_ETC1_RGB8_OES: { |
- if (width <= 0 || height <= 0) { |
- LOCAL_SET_GL_ERROR( |
- GL_INVALID_OPERATION, function_name, |
- "width or height invalid for level"); |
- return false; |
- } |
- return true; |
- } |
- case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG: |
- case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG: |
- case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: |
- case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG: { |
- if (!IsValidPVRTCSize(level, width) || |
- !IsValidPVRTCSize(level, height)) { |
- LOCAL_SET_GL_ERROR( |
- GL_INVALID_OPERATION, function_name, |
- "width or height invalid for level"); |
- return false; |
- } |
- return true; |
- } |
- default: |
- return false; |
+ if (!GLES2Util::IsValidCompressedImageSize(level, width, height, format)) { |
+ LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name, |
+ "width or height invalid for level"); |
+ return false; |
} |
+ |
+ return true; |
} |
bool GLES2DecoderImpl::ValidateCompressedTexSubDimensions( |
@@ -8473,10 +8428,13 @@ bool GLES2DecoderImpl::ValidateCompressedTexSubDimensions( |
} |
switch (format) { |
+ case GL_ATC_RGB_AMD: |
+ case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD: |
case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: |
case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: |
case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: |
- case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: { |
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: |
+ case GL_ETC1_RGB8_OES: { |
const int kBlockWidth = 4; |
const int kBlockHeight = 4; |
if ((xoffset % kBlockWidth) || (yoffset % kBlockHeight)) { |
@@ -8497,20 +8455,12 @@ bool GLES2DecoderImpl::ValidateCompressedTexSubDimensions( |
return ValidateCompressedTexDimensions( |
function_name, level, width, height, format); |
} |
- case GL_ATC_RGB_AMD: |
- case GL_ATC_RGBA_EXPLICIT_ALPHA_AMD: |
- case GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD: { |
+ case GL_ATC_RGBA_EXPLICIT_ALPHA_AMD: { |
LOCAL_SET_GL_ERROR( |
GL_INVALID_OPERATION, function_name, |
"not supported for ATC textures"); |
return false; |
} |
- case GL_ETC1_RGB8_OES: { |
- LOCAL_SET_GL_ERROR( |
- GL_INVALID_OPERATION, function_name, |
- "not supported for ECT1_RGB8_OES textures"); |
- return false; |
- } |
case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG: |
case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG: |
case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG: |
@@ -8539,6 +8489,72 @@ bool GLES2DecoderImpl::ValidateCompressedTexSubDimensions( |
} |
} |
+bool GLES2DecoderImpl::ValidateCompressedTexSubImage2D( |
+ error::Error* error, |
+ const char* function_name, |
+ GLenum target, |
+ GLint level, |
+ GLint xoffset, |
+ GLint yoffset, |
+ GLsizei width, |
+ GLsizei height, |
+ GLenum format, |
+ GLsizei image_size, |
+ const void* data) { |
+ (*error) = error::kNoError; |
+ if (!validators_->texture_target.IsValid(target)) { |
+ LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, target, "target"); |
+ return false; |
+ } |
+ if (width < 0) { |
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, "width < 0"); |
+ return false; |
+ } |
+ if (height < 0) { |
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, "height < 0"); |
+ return false; |
+ } |
+ TextureRef* texture_ref = |
+ texture_manager()->GetTextureInfoForTarget(&state_, target); |
+ if (!texture_ref) { |
+ LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name, |
+ "unknown texture for target"); |
+ return false; |
+ } |
+ Texture* texture = texture_ref->texture(); |
+ GLenum current_type = 0; |
+ GLenum internal_format = 0; |
+ if (!texture->GetLevelType(target, level, ¤t_type, &internal_format)) { |
+ LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name, |
+ "level does not exist."); |
+ return false; |
+ } |
+ if (async_pixel_transfer_manager_->AsyncTransferIsInProgress(texture_ref)) { |
+ LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name, |
+ "async upload pending for texture"); |
+ return false; |
+ } |
+ if (!ValidateCompressedTexFuncData(function_name, width, height, format, |
+ image_size)) { |
+ return false; |
+ } |
+ if (!ValidateCompressedTexSubDimensions(function_name, target, level, xoffset, |
+ yoffset, width, height, format, |
+ texture)) { |
+ return false; |
+ } |
+ if (!texture->ValidForTexture(target, level, xoffset, yoffset, width, height, |
+ GL_UNSIGNED_BYTE)) { |
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, "bad dimensions."); |
+ return false; |
+ } |
+ if (data == NULL) { |
+ (*error) = error::kOutOfBounds; |
+ return false; |
+ } |
+ return true; |
+} |
+ |
error::Error GLES2DecoderImpl::DoCompressedTexImage2D( |
GLenum target, |
GLint level, |
@@ -10587,6 +10603,149 @@ void GLES2DecoderImpl::DoCopyTextureCHROMIUM( |
DoDidUseTexImageIfNeeded(source_texture, source_texture->target()); |
} |
+void GLES2DecoderImpl::DoCopyCompressedTextureCHROMIUM(GLenum target, |
+ GLuint source_id, |
+ GLuint dest_id, |
+ GLenum internal_format, |
+ GLenum dest_type) { |
+ TRACE_EVENT0("gpu", "GLES2DecoderImpl::DoCopyCompressedTextureCHROMIUM"); |
+ |
+ TextureRef* dest_texture_ref = GetTexture(dest_id); |
+ TextureRef* source_texture_ref = GetTexture(source_id); |
+ |
+ if (!source_texture_ref || !dest_texture_ref) { |
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCopyCompressedTextureCHROMIUM", |
+ "unknown texture id"); |
+ return; |
+ } |
+ |
+ if (GL_TEXTURE_2D != target) { |
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCopyCompressedTextureCHROMIUM", |
+ "invalid texture target"); |
+ return; |
+ } |
+ |
+ Texture* source_texture = source_texture_ref->texture(); |
+ Texture* dest_texture = dest_texture_ref->texture(); |
+ if (dest_texture->target() != GL_TEXTURE_2D || |
+ (source_texture->target() != GL_TEXTURE_2D && |
+ source_texture->target() != GL_TEXTURE_RECTANGLE_ARB && |
+ source_texture->target() != GL_TEXTURE_EXTERNAL_OES)) { |
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCopyCompressedTextureCHROMIUM", |
+ "invalid texture target binding"); |
+ return; |
+ } |
+ |
+ gfx::GLImage* image = |
+ source_texture->GetLevelImage(source_texture->target(), 0); |
+ if (!image) { |
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCopyCompressedTextureCHROMIUM", |
+ "source texture has no level 0"); |
+ return; |
+ } |
+ |
+ gfx::Size size = image->GetSize(); |
+ int source_width = size.width(); |
+ int source_height = size.height(); |
+ if (source_width <= 0 || source_height <= 0) { |
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCopyCompressedTextureCHROMIUM", |
+ "invalid image size"); |
+ return; |
+ } |
+ |
+ // Clear the source texture if necessary. |
+ if (!texture_manager()->ClearTextureLevel(this, source_texture_ref, |
+ source_texture->target(), 0)) { |
+ LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY, "glCopyCompressedTextureCHROMIUM", |
+ "dimensions too big"); |
+ return; |
+ } |
+ |
+ GLenum source_type = 0; |
+ GLenum source_internal_format = 0; |
+ source_texture->GetLevelType(source_texture->target(), 0, &source_type, |
+ &source_internal_format); |
+ |
+ // The destination format should be one of the supported compressed formats. |
+ bool valid_dest_format = |
+ internal_format == GL_ATC_RGB_AMD || |
+ internal_format == GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD || |
+ internal_format == GL_COMPRESSED_RGB_S3TC_DXT1_EXT || |
+ internal_format == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT || |
+ internal_format == GL_ETC1_RGB8_OES; |
+ bool valid_source_format = source_internal_format == GL_ALPHA || |
+ source_internal_format == GL_RGB || |
+ source_internal_format == GL_RGBA || |
+ source_internal_format == GL_LUMINANCE || |
+ source_internal_format == GL_LUMINANCE_ALPHA || |
+ source_internal_format == GL_BGRA_EXT; |
+ if (!valid_source_format || !valid_dest_format) { |
+ LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glCopyCompressedTextureCHROMIUM", |
+ "invalid internal format"); |
+ return; |
+ } |
+ |
+ // Defer initializing the CopyTextureCHROMIUMResourceManager until it is |
+ // needed because it takes 10s of milliseconds to initialize. |
+ if (!copy_texture_CHROMIUM_.get()) { |
+ LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glCopyCompressedTextureCHROMIUM"); |
+ copy_texture_CHROMIUM_.reset(new CopyTextureCHROMIUMResourceManager()); |
+ copy_texture_CHROMIUM_->Initialize(this); |
+ RestoreCurrentFramebufferBindings(); |
+ if (LOCAL_PEEK_GL_ERROR("glCopyCompressedTextureCHROMIUM") != GL_NO_ERROR) |
+ return; |
+ } |
+ |
+ GLenum dest_type_previous = dest_type; |
+ GLenum dest_internal_format = internal_format; |
+ int dest_width = 0, dest_height = 0; |
+ bool dest_level_defined = |
+ dest_texture->GetLevelSize(GL_TEXTURE_2D, 0, &dest_width, &dest_height); |
+ |
+ if (dest_level_defined) { |
+ dest_texture->GetLevelType(GL_TEXTURE_2D, 0, &dest_type_previous, |
+ &dest_internal_format); |
+ } |
+ |
+ // Resize the destination texture to the dimensions of the source texture. |
+ if (!dest_level_defined || dest_width != source_width || |
+ dest_height != source_height || dest_internal_format != internal_format || |
+ dest_type_previous != dest_type) { |
+ // Compute image byte size. |
+ GLsizei image_size = |
+ source_width * source_height * BitsPerPixel(internal_format) / 8; |
+ |
+ // Ensure that the glCompressedTexImage2D succeeds. |
+ LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glCopyCompressedTextureCHROMIUM"); |
+ glBindTexture(GL_TEXTURE_2D, dest_texture->service_id()); |
+ glCompressedTexImage2D(GL_TEXTURE_2D, 0, internal_format, source_width, |
+ source_height, 0, image_size, NULL); |
+ |
+ GLenum error = LOCAL_PEEK_GL_ERROR("glCopyCompressedTextureCHROMIUM"); |
+ if (error != GL_NO_ERROR) { |
+ RestoreCurrentTextureBindings(&state_, GL_TEXTURE_2D); |
+ return; |
+ } |
+ |
+ texture_manager()->SetLevelInfo( |
+ dest_texture_ref, GL_TEXTURE_2D, 0, internal_format, source_width, |
+ source_height, 1, 0, internal_format, dest_type, true); |
+ } else { |
+ texture_manager()->SetLevelCleared(dest_texture_ref, GL_TEXTURE_2D, 0, |
+ true); |
+ } |
+ |
+ ScopedModifyPixels modify(dest_texture_ref); |
+ |
+ DCHECK(!unpack_flip_y_); |
+ DCHECK(!(unpack_premultiply_alpha_ ^ unpack_unpremultiply_alpha_)); |
+ |
+ // Copying compressed textures is only supported using GLImage::CopyTexImage. |
+ glBindTexture(GL_TEXTURE_2D, dest_texture->service_id()); |
+ bool copy_result = image->CopyTexImage(GL_TEXTURE_2D); |
+ DCHECK(copy_result); |
+} |
+ |
static GLenum ExtractTypeFromStorageFormat(GLenum internalformat) { |
switch (internalformat) { |
case GL_RGB565: |
@@ -11472,6 +11631,214 @@ error::Error GLES2DecoderImpl::HandleAsyncTexSubImage2DCHROMIUM( |
return error::kNoError; |
} |
+error::Error GLES2DecoderImpl::HandleAsyncCompressedTexImage2DCHROMIUM( |
+ uint32 immediate_data_size, |
+ const void* cmd_data) { |
+ const gles2::cmds::AsyncCompressedTexImage2DCHROMIUM& c = |
+ *static_cast<const gles2::cmds::AsyncCompressedTexImage2DCHROMIUM*>( |
+ cmd_data); |
+ GLenum target = static_cast<GLenum>(c.target); |
+ GLint level = static_cast<GLint>(c.level); |
+ // TODO(kloveless): Change HandleAsyncTexImage2DCHROMIUM command to use |
+ // unsigned integer for internalformat. |
+ GLenum internal_format = static_cast<GLenum>(c.internalformat); |
+ GLsizei width = static_cast<GLsizei>(c.width); |
+ GLsizei height = static_cast<GLsizei>(c.height); |
+ GLint border = static_cast<GLint>(c.border); |
+ GLsizei image_size = static_cast<GLenum>(c.imagesize); |
+ uint32 pixels_shm_id = static_cast<uint32>(c.pixels_shm_id); |
+ uint32 pixels_shm_offset = static_cast<uint32>(c.pixels_shm_offset); |
+ uint32 async_upload_token = static_cast<uint32>(c.async_upload_token); |
+ uint32 sync_data_shm_id = static_cast<uint32>(c.sync_data_shm_id); |
+ uint32 sync_data_shm_offset = static_cast<uint32>(c.sync_data_shm_offset); |
+ |
+ base::ScopedClosureRunner scoped_completion_callback; |
+ if (async_upload_token) { |
+ base::Closure completion_closure = AsyncUploadTokenCompletionClosure( |
+ async_upload_token, sync_data_shm_id, sync_data_shm_offset); |
+ if (completion_closure.is_null()) |
+ return error::kInvalidArguments; |
+ |
+ scoped_completion_callback.Reset(completion_closure); |
+ } |
+ |
+ const void* pixels = NULL; |
+ if (pixels_shm_id != 0 || pixels_shm_offset != 0) { |
+ pixels = GetSharedMemoryAs<const void*>(pixels_shm_id, pixels_shm_offset, |
+ image_size); |
+ if (!pixels) { |
+ return error::kOutOfBounds; |
+ } |
+ } |
+ |
+ TextureManager::DoCompressedTexImage2DArguments args = {target, |
+ level, |
+ internal_format, |
+ width, |
+ height, |
+ border, |
+ image_size, |
+ pixels}; |
+ TextureRef* texture_ref; |
+ // All the normal glCompressedTexImage2D validation. |
+ if (!texture_manager()->ValidateCompressedTexImage2D( |
+ &state_, "glAsyncCompressedTexImage2DCHROMIUM", args, &texture_ref)) { |
+ return error::kNoError; |
+ } |
+ |
+ // Extra async validation. |
+ Texture* texture = texture_ref->texture(); |
+ if (!ValidateAsyncTransfer("glAsyncCompressedTexImage2DCHROMIUM", texture_ref, |
+ target, level, pixels)) |
+ return error::kNoError; |
+ |
+ // Don't allow async redefinition of a textures. |
+ if (texture->IsDefined()) { |
+ LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, |
+ "glAsyncCompressedTexImage2DCHROMIUM", |
+ "already defined"); |
+ return error::kNoError; |
+ } |
+ |
+ if (!EnsureGPUMemoryAvailable(image_size)) { |
+ LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY, "glAsyncCompressedTexImage2DCHROMIUM", |
+ "out of memory"); |
+ return error::kNoError; |
+ } |
+ |
+ // Setup the parameters. |
+ AsyncCompressedTexImage2DParams tex_params = { |
+ target, |
+ level, |
+ static_cast<GLenum>(internal_format), |
+ width, |
+ height, |
+ border, |
+ image_size}; |
+ AsyncMemoryParams mem_params(GetSharedMemoryBuffer(c.pixels_shm_id), |
+ c.pixels_shm_offset, image_size); |
+ |
+ // Set up the async state if needed, and make the texture |
+ // immutable so the async state stays valid. The level info |
+ // is set up lazily when the transfer completes. |
+ AsyncPixelTransferDelegate* delegate = |
+ async_pixel_transfer_manager_->CreatePixelTransferDelegate(texture_ref, |
+ tex_params); |
+ texture->SetImmutable(true); |
+ |
+ delegate->AsyncCompressedTexImage2D( |
+ tex_params, mem_params, |
+ base::Bind(&TextureManager::SetCompressedLevelInfoFromParams, |
+ // The callback is only invoked if the transfer delegate still |
+ // exists, which implies through manager->texture_ref->state |
+ // ownership that both of these pointers are valid. |
+ base::Unretained(texture_manager()), |
+ base::Unretained(texture_ref), tex_params)); |
+ return error::kNoError; |
+} |
+ |
+error::Error GLES2DecoderImpl::HandleAsyncCompressedTexSubImage2DCHROMIUM( |
+ uint32 immediate_data_size, |
+ const void* cmd_data) { |
+ const gles2::cmds::AsyncCompressedTexSubImage2DCHROMIUM& c = |
+ *static_cast<const gles2::cmds::AsyncCompressedTexSubImage2DCHROMIUM*>( |
+ cmd_data); |
+ TRACE_EVENT0("gpu", |
+ "GLES2DecoderImpl::HandleAsyncCompressedTexSubImage2DCHROMIUM"); |
+ GLenum target = static_cast<GLenum>(c.target); |
+ GLint level = static_cast<GLint>(c.level); |
+ GLint xoffset = static_cast<GLint>(c.xoffset); |
+ GLint yoffset = static_cast<GLint>(c.yoffset); |
+ GLsizei width = static_cast<GLsizei>(c.width); |
+ GLsizei height = static_cast<GLsizei>(c.height); |
+ GLenum format = static_cast<GLenum>(c.format); |
+ GLsizei image_size = static_cast<GLsizei>(c.imagesize); |
+ uint32 async_upload_token = static_cast<uint32>(c.async_upload_token); |
+ uint32 sync_data_shm_id = static_cast<uint32>(c.sync_data_shm_id); |
+ uint32 sync_data_shm_offset = static_cast<uint32>(c.sync_data_shm_offset); |
+ |
+ base::ScopedClosureRunner scoped_completion_callback; |
+ if (async_upload_token) { |
+ base::Closure completion_closure = AsyncUploadTokenCompletionClosure( |
+ async_upload_token, sync_data_shm_id, sync_data_shm_offset); |
+ if (completion_closure.is_null()) |
+ return error::kInvalidArguments; |
+ |
+ scoped_completion_callback.Reset(completion_closure); |
+ } |
+ |
+ const void* pixels = GetSharedMemoryAs<const void*>( |
+ c.data_shm_id, c.data_shm_offset, image_size); |
+ |
+ // All the normal glCompressedTexSubImage2D validation. |
+ error::Error error = error::kNoError; |
+ if (!ValidateCompressedTexSubImage2D( |
+ &error, "glAsyncCompressedTexSubImage2DCHROMIUM", target, level, |
+ xoffset, yoffset, width, height, format, image_size, pixels)) { |
+ return error; |
+ } |
+ |
+ // Extra async validation. |
+ TextureRef* texture_ref = |
+ texture_manager()->GetTextureInfoForTarget(&state_, target); |
+ Texture* texture = texture_ref->texture(); |
+ if (!ValidateAsyncTransfer("glAsyncCompressedTexSubImage2DCHROMIUM", |
+ texture_ref, target, level, pixels)) |
+ return error::kNoError; |
+ |
+ // Guarantee async textures are always 'cleared' as follows: |
+ // - AsyncCompressedTexImage2D can not redefine an existing texture |
+ // - AsyncCompressedTexImage2D must initialize the entire image via non-null |
+ // buffer. |
+ // - AsyncCompressedTexSubImage2D clears synchronously if not already cleared. |
+ // - Textures become immutable after an async call. |
+ // This way we know in all cases that an async texture is always clear. |
+ if (!texture->SafeToRenderFrom()) { |
+ if (!texture_manager()->ClearTextureLevel(this, texture_ref, target, |
+ level)) { |
+ LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY, |
+ "glAsyncCompressedTexSubImage2DCHROMIUM", |
+ "dimensions too big"); |
+ return error::kNoError; |
+ } |
+ } |
+ |
+ // Setup the parameters. |
+ AsyncCompressedTexSubImage2DParams tex_params = {target, |
+ level, |
+ xoffset, |
+ yoffset, |
+ width, |
+ height, |
+ static_cast<GLenum>(format), |
+ image_size}; |
+ AsyncMemoryParams mem_params(GetSharedMemoryBuffer(c.data_shm_id), |
+ c.data_shm_offset, image_size); |
+ AsyncPixelTransferDelegate* delegate = |
+ async_pixel_transfer_manager_->GetPixelTransferDelegate(texture_ref); |
+ if (!delegate) { |
+ // TODO(epenner): We may want to enforce exclusive use |
+ // of async APIs in which case this should become an error, |
+ // (the texture should have been async defined). |
+ AsyncCompressedTexImage2DParams define_params = { |
+ target, level, 0, 0, 0, 0, 0}; |
+ texture->GetLevelSize(target, level, &define_params.width, |
+ &define_params.height); |
+ GLenum dummy_type; |
+ texture->GetLevelType(target, level, &dummy_type, |
+ &define_params.internal_format); |
+ |
+ // Set up the async state if needed, and make the texture |
+ // immutable so the async state stays valid. |
+ delegate = async_pixel_transfer_manager_->CreatePixelTransferDelegate( |
+ texture_ref, define_params); |
+ texture->SetImmutable(true); |
+ } |
+ |
+ delegate->AsyncCompressedTexSubImage2D(tex_params, mem_params); |
+ return error::kNoError; |
+} |
+ |
error::Error GLES2DecoderImpl::HandleWaitAsyncTexImage2DCHROMIUM( |
uint32 immediate_data_size, |
const void* cmd_data) { |