diff options
author | kloveless@chromium.org <kloveless@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-14 01:04:44 +0000 |
---|---|---|
committer | kloveless@chromium.org <kloveless@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-14 01:04:44 +0000 |
commit | c986af50bebe985a8b610ad20151f571f9548d70 (patch) | |
tree | ffd60c8f14b0c8ec31de2d12d5d3b2f21ab25b58 /gpu | |
parent | 4fe5b9dc4018358bd042276cb2bce7391698c36c (diff) | |
download | chromium_src-c986af50bebe985a8b610ad20151f571f9548d70.zip chromium_src-c986af50bebe985a8b610ad20151f571f9548d70.tar.gz chromium_src-c986af50bebe985a8b610ad20151f571f9548d70.tar.bz2 |
Moved DoTexImage2D and its validation into the TextureManager.
Added DecoderTextureState and DecoderFramebufferState to hold information used by those managers, but were decoder specific.
To simplify passing arguments around, [ValidateAnd]DoTextImage2d take a structure.
Review URL: https://chromiumcodereview.appspot.com/19471009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@217417 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu')
-rwxr-xr-x | gpu/command_buffer/build_gles2_cmd_buffer.py | 14 | ||||
-rw-r--r-- | gpu/command_buffer/service/framebuffer_manager.h | 9 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder.cc | 432 | ||||
-rw-r--r-- | gpu/command_buffer/service/gles2_cmd_decoder_autogen.h | 14 | ||||
-rw-r--r-- | gpu/command_buffer/service/texture_manager.cc | 234 | ||||
-rw-r--r-- | gpu/command_buffer/service/texture_manager.h | 81 |
6 files changed, 440 insertions, 344 deletions
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py index 6555da2..a6f13c1 100755 --- a/gpu/command_buffer/build_gles2_cmd_buffer.py +++ b/gpu/command_buffer/build_gles2_cmd_buffer.py @@ -62,13 +62,15 @@ _GL_TYPES = { _CAPABILITY_FLAGS = [ {'name': 'blend'}, {'name': 'cull_face'}, - {'name': 'depth_test', 'state_flag': 'clear_state_dirty_'}, + {'name': 'depth_test', 'state_flag': 'framebuffer_state_.clear_state_dirty'}, {'name': 'dither', 'default': True}, {'name': 'polygon_offset_fill'}, {'name': 'sample_alpha_to_coverage'}, {'name': 'sample_coverage'}, - {'name': 'scissor_test', 'state_flag': 'clear_state_dirty_'}, - {'name': 'stencil_test', 'state_flag': 'clear_state_dirty_'}, + {'name': 'scissor_test', + 'state_flag': 'framebuffer_state_.clear_state_dirty'}, + {'name': 'stencil_test', + 'state_flag': 'framebuffer_state_.clear_state_dirty'}, ] _STATES = { @@ -101,7 +103,7 @@ _STATES = { {'name': 'color_mask_blue', 'type': 'GLboolean', 'default': 'true'}, {'name': 'color_mask_alpha', 'type': 'GLboolean', 'default': 'true'}, ], - 'state_flag': 'clear_state_dirty_', + 'state_flag': 'framebuffer_state_.clear_state_dirty', }, 'ClearStencil': { 'type': 'Normal', @@ -242,7 +244,7 @@ _STATES = { 'StencilMask': { 'type': 'FrontBack', 'func': 'StencilMaskSeparate', - 'state_flag': 'clear_state_dirty_', + 'state_flag': 'framebuffer_state_.clear_state_dirty', 'states': [ { 'name': 'stencil_front_writemask', @@ -400,7 +402,7 @@ _STATES = { 'states': [ {'name': 'depth_mask', 'type': 'GLboolean', 'default': 'true'}, ], - 'state_flag': 'clear_state_dirty_', + 'state_flag': 'framebuffer_state_.clear_state_dirty', }, 'Scissor': { 'type': 'Normal', diff --git a/gpu/command_buffer/service/framebuffer_manager.h b/gpu/command_buffer/service/framebuffer_manager.h index 176e3e2..aa11118 100644 --- a/gpu/command_buffer/service/framebuffer_manager.h +++ b/gpu/command_buffer/service/framebuffer_manager.h @@ -180,6 +180,15 @@ class GPU_EXPORT Framebuffer : public base::RefCounted<Framebuffer> { DISALLOW_COPY_AND_ASSIGN(Framebuffer); }; +struct DecoderFramebufferState { + DecoderFramebufferState(): + clear_state_dirty(true) {} + + // State saved for clearing so we can clear render buffers and then + // restore to these values. + bool clear_state_dirty; +}; + // This class keeps track of the frambebuffers and their attached renderbuffers // so we can correctly clear them. class GPU_EXPORT FramebufferManager { diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index a9b1f1e..44a0134 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -349,18 +349,6 @@ class ScopedResolvedFrameBufferBinder { DISALLOW_COPY_AND_ASSIGN(ScopedResolvedFrameBufferBinder); }; -// This class records texture upload time when in scope. -class ScopedTextureUploadTimer { - public: - explicit ScopedTextureUploadTimer(GLES2DecoderImpl* decoder); - ~ScopedTextureUploadTimer(); - - private: - GLES2DecoderImpl* decoder_; - base::TimeTicks begin_time_; - DISALLOW_COPY_AND_ASSIGN(ScopedTextureUploadTimer); -}; - // Encapsulates an OpenGL texture. class BackTexture { public: @@ -651,7 +639,6 @@ class GLES2DecoderImpl : public GLES2Decoder { friend class ScopedFrameBufferBinder; friend class ScopedGLErrorSuppressor; friend class ScopedResolvedFrameBufferBinder; - friend class ScopedTextureUploadTimer; friend class BackTexture; friend class BackRenderbuffer; friend class BackFramebuffer; @@ -813,33 +800,6 @@ class GLES2DecoderImpl : public GLES2Decoder { GLsizei width, GLsizei height); - // Validation for TexImage2D commands. - bool ValidateTexImage2D( - const char* function_name, - GLenum target, - GLint level, - GLenum internal_format, - GLsizei width, - GLsizei height, - GLint border, - GLenum format, - GLenum type, - const void* pixels, - uint32 pixels_size); - - // Wrapper for TexImage2D commands. - void DoTexImage2D( - GLenum target, - GLint level, - GLenum internal_format, - GLsizei width, - GLsizei height, - GLint border, - GLenum format, - GLenum type, - const void* pixels, - uint32 pixels_size); - // Validation for TexSubImage2D. bool ValidateTexSubImage2D( error::Error* error, @@ -1427,46 +1387,6 @@ class GLES2DecoderImpl : public GLES2Decoder { bool instanced, GLenum mode, GLsizei count, GLenum type, int32 offset, GLsizei primcount); - // Gets the texture id for a given target. - TextureRef* GetTextureInfoForTarget(GLenum target) { - TextureUnit& unit = state_.texture_units[state_.active_texture_unit]; - TextureRef* texture = NULL; - switch (target) { - case GL_TEXTURE_2D: - texture = unit.bound_texture_2d.get(); - break; - case GL_TEXTURE_CUBE_MAP: - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - texture = unit.bound_texture_cube_map.get(); - break; - case GL_TEXTURE_EXTERNAL_OES: - texture = unit.bound_texture_external_oes.get(); - break; - case GL_TEXTURE_RECTANGLE_ARB: - texture = unit.bound_texture_rectangle_arb.get(); - break; - default: - NOTREACHED(); - return NULL; - } - return texture; - } - - TextureRef* GetTextureInfoForTargetUnlessDefault( - GLenum target) { - TextureRef* texture = GetTextureInfoForTarget(target); - if (!texture) - return NULL; - if (texture == texture_manager()->GetDefaultTextureInfo(target)) - return NULL; - return texture; - } - GLenum GetBindTargetForSamplerType(GLenum type) { DCHECK(type == GL_SAMPLER_2D || type == GL_SAMPLER_CUBE || type == GL_SAMPLER_EXTERNAL_OES || type == GL_SAMPLER_2D_RECT_ARB); @@ -1642,10 +1562,6 @@ class GLES2DecoderImpl : public GLES2Decoder { // The size of fiixed attrib buffer. GLsizei fixed_attrib_buffer_size_; - // state saved for clearing so we can clear render buffers and then - // restore to these values. - bool clear_state_dirty_; - // The offscreen frame buffer that the client renders to. With EGL, the // depth and stencil buffers are separate. With regular GL there is a single // packed depth stencil buffer in offscreen_target_depth_render_buffer_. @@ -1692,8 +1608,6 @@ class GLES2DecoderImpl : public GLES2Decoder { // Backbuffer attachments that are currently undefined. uint32 backbuffer_needs_clear_bits_; - bool teximage2d_faster_than_texsubimage2d_; - // The current decoder error. error::Error current_decoder_error_; @@ -1707,10 +1621,6 @@ class GLES2DecoderImpl : public GLES2Decoder { const Validators* validators_; scoped_refptr<FeatureInfo> feature_info_; - // This indicates all the following texSubImage2D calls that are part of the - // failed texImage2D call should be ignored. - bool tex_image_2d_failed_; - int frame_number_; bool has_robustness_extension_; @@ -1744,10 +1654,12 @@ class GLES2DecoderImpl : public GLES2Decoder { GLsizei viewport_max_height_; // Command buffer stats. - int texture_upload_count_; - base::TimeDelta total_texture_upload_time_; base::TimeDelta total_processing_commands_time_; + // States related to each manager. + DecoderTextureState texture_state_; + DecoderFramebufferState framebuffer_state_; + scoped_ptr<GPUTracer> gpu_tracer_; std::queue<linked_ptr<FenceCallback> > pending_readpixel_fences_; @@ -1881,17 +1793,6 @@ ScopedResolvedFrameBufferBinder::~ScopedResolvedFrameBufferBinder() { } } -ScopedTextureUploadTimer::ScopedTextureUploadTimer(GLES2DecoderImpl* decoder) - : decoder_(decoder), - begin_time_(base::TimeTicks::HighResNow()) { -} - -ScopedTextureUploadTimer::~ScopedTextureUploadTimer() { - decoder_->texture_upload_count_++; - decoder_->total_texture_upload_time_ += - base::TimeTicks::HighResNow() - begin_time_; -} - BackTexture::BackTexture(GLES2DecoderImpl* decoder) : decoder_(decoder), memory_tracker_(decoder->memory_tracker(), MemoryTracker::kUnmanaged), @@ -2156,7 +2057,6 @@ GLES2DecoderImpl::GLES2DecoderImpl(ContextGroup* group) attrib_0_size_(0), fixed_attrib_buffer_id_(0), fixed_attrib_buffer_size_(0), - clear_state_dirty_(true), offscreen_target_color_format_(0), offscreen_target_depth_format_(0), offscreen_target_stencil_format_(0), @@ -2167,12 +2067,10 @@ GLES2DecoderImpl::GLES2DecoderImpl(ContextGroup* group) back_buffer_has_depth_(false), back_buffer_has_stencil_(false), backbuffer_needs_clear_bits_(0), - teximage2d_faster_than_texsubimage2d_(true), current_decoder_error_(error::kNoError), use_shader_translator_(true), validators_(group_->feature_info()->validators()), feature_info_(group_->feature_info()), - tex_image_2d_failed_(false), frame_number_(0), has_robustness_extension_(false), reset_status_(GL_NO_ERROR), @@ -2185,8 +2083,7 @@ GLES2DecoderImpl::GLES2DecoderImpl(ContextGroup* group) service_logging_(CommandLine::ForCurrentProcess()->HasSwitch( switches::kEnableGPUServiceLoggingGPU)), viewport_max_width_(0), - viewport_max_height_(0), - texture_upload_count_(0) { + viewport_max_height_(0) { DCHECK(group); attrib_0_value_.v[0] = 0.0f; @@ -2207,7 +2104,7 @@ GLES2DecoderImpl::GLES2DecoderImpl(ContextGroup* group) // TODO(gman): Consider setting this based on GPU and/or driver. if (IsAngle()) { - teximage2d_faster_than_texsubimage2d_ = false; + texture_state_.teximage2d_faster_than_texsubimage2d = false; } } @@ -2717,7 +2614,7 @@ void GLES2DecoderImpl::DeleteFramebuffersHelper( if (framebuffer && !framebuffer->IsDeleted()) { if (framebuffer == state_.bound_draw_framebuffer.get()) { state_.bound_draw_framebuffer = NULL; - clear_state_dirty_ = true; + framebuffer_state_.clear_state_dirty = true; GLenum target = supports_separate_framebuffer_binds ? GL_DRAW_FRAMEBUFFER_EXT : GL_FRAMEBUFFER; glBindFramebufferEXT(target, GetBackbufferServiceId()); @@ -2761,7 +2658,7 @@ void GLES2DecoderImpl::DeleteRenderbuffersHelper( ->UnbindRenderbuffer(GL_FRAMEBUFFER, renderbuffer); } } - clear_state_dirty_ = true; + framebuffer_state_.clear_state_dirty = true; RemoveRenderbuffer(client_ids[ii]); } } @@ -2776,7 +2673,7 @@ void GLES2DecoderImpl::DeleteTexturesHelper( if (texture_ref) { Texture* texture = texture_ref->texture(); if (texture->IsAttachedToFramebuffer()) { - clear_state_dirty_ = true; + framebuffer_state_.clear_state_dirty = true; } // Unbind texture_ref from texture_ref units. for (size_t jj = 0; jj < state_.texture_units.size(); ++jj) { @@ -2835,7 +2732,7 @@ bool GLES2DecoderImpl::MakeCurrent() { if (workarounds().unbind_fbo_on_context_switch) RestoreFramebufferBindings(); - clear_state_dirty_ = true; + framebuffer_state_.clear_state_dirty = true; return true; } @@ -2879,7 +2776,7 @@ static void RebindCurrentFramebuffer( } void GLES2DecoderImpl::RestoreCurrentFramebufferBindings() { - clear_state_dirty_ = true; + framebuffer_state_.clear_state_dirty = true; if (!features().chromium_framebuffer_multisample) { RebindCurrentFramebuffer( @@ -3075,7 +2972,8 @@ void GLES2DecoderImpl::UpdateParentTextureInfo() { offscreen_saved_color_texture_info_.get(), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - TextureRef* texture_ref = GetTextureInfoForTarget(target); + TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget( + &state_, target); glBindTexture(target, texture_ref ? texture_ref->service_id() : 0); } @@ -3127,12 +3025,12 @@ bool GLES2DecoderImpl::GetServiceTextureId(uint32 client_texture_id, } uint32 GLES2DecoderImpl::GetTextureUploadCount() { - return texture_upload_count_ + + return texture_state_.texture_upload_count + async_pixel_transfer_manager_->GetTextureUploadCount(); } base::TimeDelta GLES2DecoderImpl::GetTotalTextureUploadTime() { - return total_texture_upload_time_ + + return texture_state_.total_texture_upload_time + async_pixel_transfer_manager_->GetTotalTextureUploadTime(); } @@ -3678,7 +3576,7 @@ bool GLES2DecoderImpl::BoundFramebufferHasStencilAttachment() { } void GLES2DecoderImpl::ApplyDirtyState() { - if (clear_state_dirty_) { + if (framebuffer_state_.clear_state_dirty) { glColorMask( state_.color_mask_red, state_.color_mask_green, state_.color_mask_blue, state_.color_mask_alpha && @@ -3696,7 +3594,7 @@ void GLES2DecoderImpl::ApplyDirtyState() { EnableDisable(GL_CULL_FACE, state_.enable_flags.cull_face); EnableDisable(GL_SCISSOR_TEST, state_.enable_flags.scissor_test); EnableDisable(GL_BLEND, state_.enable_flags.blend); - clear_state_dirty_ = false; + framebuffer_state_.clear_state_dirty = false; } } @@ -3804,7 +3702,7 @@ void GLES2DecoderImpl::DoBindFramebuffer(GLenum target, GLuint client_id) { state_.bound_read_framebuffer = framebuffer; } - clear_state_dirty_ = true; + framebuffer_state_.clear_state_dirty = true; // If we are rendering to the backbuffer get the FBO id for any simulated // backbuffer. @@ -3982,7 +3880,8 @@ void GLES2DecoderImpl::DoEnableVertexAttribArray(GLuint index) { } void GLES2DecoderImpl::DoGenerateMipmap(GLenum target) { - TextureRef* texture_ref = GetTextureInfoForTarget(target); + TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget( + &state_, target); if (!texture_ref || !texture_manager()->CanGenerateMipmaps(texture_ref)) { LOCAL_SET_GL_ERROR( @@ -4758,7 +4657,7 @@ void GLES2DecoderImpl::DoFramebufferRenderbuffer( framebuffer->AttachRenderbuffer(attachment, renderbuffer); } if (framebuffer == state_.bound_draw_framebuffer.get()) { - clear_state_dirty_ = true; + framebuffer_state_.clear_state_dirty = true; } OnFboChanged(); } @@ -4842,7 +4741,7 @@ void GLES2DecoderImpl::ClearUnclearedAttachments( } void GLES2DecoderImpl::RestoreClearState() { - clear_state_dirty_ = true; + framebuffer_state_.clear_state_dirty = true; glClearColor( state_.color_clear_red, state_.color_clear_green, state_.color_clear_blue, state_.color_clear_alpha); @@ -4942,7 +4841,7 @@ void GLES2DecoderImpl::DoFramebufferTexture2DCommon( samples); } if (framebuffer == state_.bound_draw_framebuffer.get()) { - clear_state_dirty_ = true; + framebuffer_state_.clear_state_dirty = true; } OnFboChanged(); } @@ -5181,7 +5080,8 @@ void GLES2DecoderImpl::DoLinkProgram(GLuint program_id) { void GLES2DecoderImpl::DoTexParameterf( GLenum target, GLenum pname, GLfloat param) { - TextureRef* texture = GetTextureInfoForTarget(target); + TextureRef* texture = texture_manager()->GetTextureInfoForTarget( + &state_, target); if (!texture) { LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexParameterf", "unknown texture"); return; @@ -5194,7 +5094,8 @@ void GLES2DecoderImpl::DoTexParameterf( void GLES2DecoderImpl::DoTexParameteri( GLenum target, GLenum pname, GLint param) { - TextureRef* texture = GetTextureInfoForTarget(target); + TextureRef* texture = texture_manager()->GetTextureInfoForTarget( + &state_, target); if (!texture) { LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexParameteri", "unknown texture"); return; @@ -5206,7 +5107,8 @@ void GLES2DecoderImpl::DoTexParameteri( void GLES2DecoderImpl::DoTexParameterfv( GLenum target, GLenum pname, const GLfloat* params) { - TextureRef* texture = GetTextureInfoForTarget(target); + TextureRef* texture = texture_manager()->GetTextureInfoForTarget( + &state_, target); if (!texture) { LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexParameterfv", "unknown texture"); return; @@ -5219,7 +5121,8 @@ void GLES2DecoderImpl::DoTexParameterfv( void GLES2DecoderImpl::DoTexParameteriv( GLenum target, GLenum pname, const GLint* params) { - TextureRef* texture = GetTextureInfoForTarget(target); + TextureRef* texture = texture_manager()->GetTextureInfoForTarget( + &state_, target); if (!texture) { LOCAL_SET_GL_ERROR( GL_INVALID_VALUE, "glTexParameteriv", "unknown texture"); @@ -7420,7 +7323,8 @@ bool GLES2DecoderImpl::ClearLevel( } y += tile_height; } - TextureRef* texture = GetTextureInfoForTarget(bind_target); + TextureRef* texture = texture_manager()->GetTextureInfoForTarget( + &state_, bind_target); glBindTexture(bind_target, texture ? texture->service_id() : 0); return true; } @@ -7595,7 +7499,8 @@ error::Error GLES2DecoderImpl::DoCompressedTexImage2D( "glCompressedTexImage2D", "dimensions out of range"); return error::kNoError; } - TextureRef* texture_ref = GetTextureInfoForTarget(target); + TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget( + &state_, target); if (!texture_ref) { LOCAL_SET_GL_ERROR( GL_INVALID_VALUE, @@ -7624,7 +7529,7 @@ error::Error GLES2DecoderImpl::DoCompressedTexImage2D( } if (texture->IsAttachedToFramebuffer()) { - clear_state_dirty_ = true; + framebuffer_state_.clear_state_dirty = true; } scoped_ptr<int8[]> zero; @@ -7759,176 +7664,16 @@ error::Error GLES2DecoderImpl::HandleCompressedTexSubImage2DBucket( return error::kNoError; } -bool GLES2DecoderImpl::ValidateTextureParameters( - const char* function_name, - GLenum target, GLenum format, GLenum type, GLint level) { - if (!feature_info_->GetTextureFormatValidator(format).IsValid(type)) { - LOCAL_SET_GL_ERROR( - GL_INVALID_OPERATION, function_name, - (std::string("invalid type ") + - GLES2Util::GetStringEnum(type) + " for format " + - GLES2Util::GetStringEnum(format)).c_str()); - return false; - } - - uint32 channels = GLES2Util::GetChannelsForFormat(format); - if ((channels & (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && level) { - LOCAL_SET_GL_ERROR( - GL_INVALID_OPERATION, function_name, - (std::string("invalid type ") + - GLES2Util::GetStringEnum(type) + " for format " + - GLES2Util::GetStringEnum(format)).c_str()); - return false; - } - return true; -} - -bool GLES2DecoderImpl::ValidateTexImage2D( - const char* function_name, - GLenum target, - GLint level, - GLenum internal_format, - GLsizei width, - GLsizei height, - GLint border, - GLenum format, - GLenum type, - const void* pixels, - uint32 pixels_size) { - if (!validators_->texture_target.IsValid(target)) { - LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, target, "target"); - return false; - } - if (!validators_->texture_format.IsValid(internal_format)) { - LOCAL_SET_GL_ERROR_INVALID_ENUM( - function_name, internal_format, "internal_format"); - return false; - } - if (!validators_->texture_format.IsValid(format)) { - LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, format, "format"); - return false; - } - if (!validators_->pixel_type.IsValid(type)) { - LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, type, "type"); - return false; - } - if (format != internal_format) { - LOCAL_SET_GL_ERROR( - GL_INVALID_OPERATION, function_name, "format != internalFormat"); - return false; - } - if (!ValidateTextureParameters(function_name, target, format, type, level)) { - return false; - } - if (!texture_manager()->ValidForTarget(target, level, width, height, 1) || - border != 0) { - LOCAL_SET_GL_ERROR( - GL_INVALID_VALUE, function_name, "dimensions out of range"); - return false; - } - if ((GLES2Util::GetChannelsForFormat(format) & - (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && pixels) { - LOCAL_SET_GL_ERROR( - GL_INVALID_OPERATION, - function_name, "can not supply data for depth or stencil textures"); - return false; - } - TextureRef* texture_ref = GetTextureInfoForTarget(target); - if (!texture_ref) { - LOCAL_SET_GL_ERROR( - GL_INVALID_OPERATION, function_name, "unknown texture for target"); - return false; - } - if (texture_ref->texture()->IsImmutable()) { - LOCAL_SET_GL_ERROR( - GL_INVALID_OPERATION, function_name, "texture is immutable"); - return false; - } - return true; -} - -void GLES2DecoderImpl::DoTexImage2D( - GLenum target, - GLint level, - GLenum internal_format, - GLsizei width, - GLsizei height, - GLint border, - GLenum format, - GLenum type, - const void* pixels, - uint32 pixels_size) { - if (!ValidateTexImage2D("glTexImage2D", target, level, internal_format, - width, height, border, format, type, pixels, pixels_size)) { - return; - } - - if (!EnsureGPUMemoryAvailable(pixels_size)) { - LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY, "glTexImage2D", "out of memory"); - return; - } - - TextureRef* texture_ref = GetTextureInfoForTarget(target); - Texture* texture = texture_ref->texture(); - GLsizei tex_width = 0; - GLsizei tex_height = 0; - GLenum tex_type = 0; - GLenum tex_format = 0; - bool level_is_same = - texture->GetLevelSize(target, level, &tex_width, &tex_height) && - texture->GetLevelType(target, level, &tex_type, &tex_format) && - width == tex_width && height == tex_height && - type == tex_type && format == tex_format; - - if (level_is_same && !pixels) { - // Just set the level texture but mark the texture as uncleared. - texture_manager()->SetLevelInfo( - texture_ref, - target, level, internal_format, width, height, 1, border, format, type, - false); - tex_image_2d_failed_ = false; - return; - } - - if (texture->IsAttachedToFramebuffer()) { - clear_state_dirty_ = true; - } - - if (!teximage2d_faster_than_texsubimage2d_ && level_is_same && pixels) { - { - ScopedTextureUploadTimer timer(this); - glTexSubImage2D(target, level, 0, 0, width, height, format, type, pixels); - } - texture_manager()->SetLevelCleared(texture_ref, target, level, true); - tex_image_2d_failed_ = false; - return; - } - - LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glTexImage2D"); - { - ScopedTextureUploadTimer timer(this); - glTexImage2D( - target, level, internal_format, width, height, border, format, type, - pixels); - } - GLenum error = LOCAL_PEEK_GL_ERROR("glTexImage2D"); - if (error == GL_NO_ERROR) { - texture_manager()->SetLevelInfo( - texture_ref, - target, level, internal_format, width, height, 1, border, format, type, - pixels != NULL); - tex_image_2d_failed_ = false; - } - return; -} - error::Error GLES2DecoderImpl::HandleTexImage2D( uint32 immediate_data_size, const cmds::TexImage2D& c) { TRACE_EVENT0("gpu", "GLES2DecoderImpl::HandleTexImage2D"); - tex_image_2d_failed_ = true; + // Set as failed for now, but if it successed, this will be set to not failed. + texture_state_.tex_image_2d_failed = true; GLenum target = static_cast<GLenum>(c.target); GLint level = static_cast<GLint>(c.level); - GLint internal_format = static_cast<GLint>(c.internalformat); + // TODO(kloveless): Change TexImage2D 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); @@ -7951,9 +7696,11 @@ error::Error GLES2DecoderImpl::HandleTexImage2D( } } - DoTexImage2D( - target, level, internal_format, width, height, border, format, type, - pixels, pixels_size); + TextureManager::DoTextImage2DArguments args = { + target, level, internal_format, width, height, border, format, type, + pixels, pixels_size}; + texture_manager()->ValidateAndDoTexImage2D( + &texture_state_, &state_, &framebuffer_state_, args); return error::kNoError; } @@ -7961,7 +7708,9 @@ error::Error GLES2DecoderImpl::HandleTexImage2DImmediate( uint32 immediate_data_size, const cmds::TexImage2DImmediate& c) { GLenum target = static_cast<GLenum>(c.target); GLint level = static_cast<GLint>(c.level); - GLint internal_format = static_cast<GLint>(c.internalformat); + // TODO(kloveless): Change TexImage2DImmediate 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); @@ -7978,9 +7727,12 @@ error::Error GLES2DecoderImpl::HandleTexImage2DImmediate( if (!pixels) { return error::kOutOfBounds; } - DoTexImage2D( - target, level, internal_format, width, height, border, format, type, - pixels, size); + + TextureManager::DoTextImage2DArguments args = { + target, level, internal_format, width, height, border, format, type, + pixels, size}; + texture_manager()->ValidateAndDoTexImage2D( + &texture_state_, &state_, &framebuffer_state_, args); return error::kNoError; } @@ -7994,7 +7746,8 @@ void GLES2DecoderImpl::DoCompressedTexSubImage2D( GLenum format, GLsizei image_size, const void * data) { - TextureRef* texture_ref = GetTextureInfoForTarget(target); + TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget( + &state_, target); if (!texture_ref) { LOCAL_SET_GL_ERROR( GL_INVALID_OPERATION, @@ -8067,7 +7820,8 @@ void GLES2DecoderImpl::DoCopyTexImage2D( GLsizei height, GLint border) { DCHECK(!ShouldDeferReads()); - TextureRef* texture_ref = GetTextureInfoForTarget(target); + TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget( + &state_, target); if (!texture_ref) { LOCAL_SET_GL_ERROR( GL_INVALID_OPERATION, @@ -8085,8 +7839,9 @@ void GLES2DecoderImpl::DoCopyTexImage2D( GL_INVALID_VALUE, "glCopyTexImage2D", "dimensions out of range"); return; } - if (!ValidateTextureParameters( - "glCopyTexImage2D", target, internal_format, GL_UNSIGNED_BYTE, level)) { + if (!texture_manager()->ValidateTextureParameters( + state_.GetErrorState(), "glCopyTexImage2D", target, internal_format, + GL_UNSIGNED_BYTE, level)) { return; } @@ -8131,7 +7886,7 @@ void GLES2DecoderImpl::DoCopyTexImage2D( gfx::Size size = GetBoundReadFrameBufferSize(); if (texture->IsAttachedToFramebuffer()) { - clear_state_dirty_ = true; + framebuffer_state_.clear_state_dirty = true; } // Clip to size to source dimensions @@ -8186,7 +7941,8 @@ void GLES2DecoderImpl::DoCopyTexSubImage2D( GLsizei width, GLsizei height) { DCHECK(!ShouldDeferReads()); - TextureRef* texture_ref = GetTextureInfoForTarget(target); + TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget( + &state_, target); if (!texture_ref) { LOCAL_SET_GL_ERROR( GL_INVALID_OPERATION, @@ -8312,7 +8068,8 @@ bool GLES2DecoderImpl::ValidateTexSubImage2D( LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, type, "type"); return false; } - TextureRef* texture_ref = GetTextureInfoForTarget(target); + TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget( + &state_, target); if (!texture_ref) { LOCAL_SET_GL_ERROR( GL_INVALID_OPERATION, @@ -8379,7 +8136,8 @@ error::Error GLES2DecoderImpl::DoTexSubImage2D( xoffset, yoffset, width, height, format, type, data)) { return error; } - TextureRef* texture_ref = GetTextureInfoForTarget(target); + TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget( + &state_, target); Texture* texture = texture_ref->texture(); GLsizei tex_width = 0; GLsizei tex_height = 0; @@ -8393,20 +8151,21 @@ error::Error GLES2DecoderImpl::DoTexSubImage2D( GL_OUT_OF_MEMORY, "glTexSubImage2D", "dimensions too big"); return error::kNoError; } - ScopedTextureUploadTimer timer(this); + ScopedTextureUploadTimer timer(&texture_state_); glTexSubImage2D( target, level, xoffset, yoffset, width, height, format, type, data); return error::kNoError; } - if (teximage2d_faster_than_texsubimage2d_ && !texture->IsImmutable()) { - ScopedTextureUploadTimer timer(this); + if (texture_state_.teximage2d_faster_than_texsubimage2d && + !texture->IsImmutable()) { + ScopedTextureUploadTimer timer(&texture_state_); // NOTE: In OpenGL ES 2.0 border is always zero and format is always the // same as internal_foramt. If that changes we'll need to look them up. glTexImage2D( target, level, format, width, height, 0, format, type, data); } else { - ScopedTextureUploadTimer timer(this); + ScopedTextureUploadTimer timer(&texture_state_); glTexSubImage2D( target, level, xoffset, yoffset, width, height, format, type, data); } @@ -8418,7 +8177,7 @@ error::Error GLES2DecoderImpl::HandleTexSubImage2D( uint32 immediate_data_size, const cmds::TexSubImage2D& c) { TRACE_EVENT0("gpu", "GLES2DecoderImpl::HandleTexSubImage2D"); GLboolean internal = static_cast<GLboolean>(c.internal); - if (internal == GL_TRUE && tex_image_2d_failed_) + if (internal == GL_TRUE && texture_state_.tex_image_2d_failed) return error::kNoError; GLenum target = static_cast<GLenum>(c.target); @@ -8444,7 +8203,7 @@ error::Error GLES2DecoderImpl::HandleTexSubImage2D( error::Error GLES2DecoderImpl::HandleTexSubImage2DImmediate( uint32 immediate_data_size, const cmds::TexSubImage2DImmediate& c) { GLboolean internal = static_cast<GLboolean>(c.internal); - if (internal == GL_TRUE && tex_image_2d_failed_) + if (internal == GL_TRUE && texture_state_.tex_image_2d_failed) return error::kNoError; GLenum target = static_cast<GLenum>(c.target); @@ -9564,7 +9323,8 @@ void GLES2DecoderImpl::DoTexImageIOSurface2DCHROMIUM( // Default target might be conceptually valid, but disallow it to avoid // accidents. - TextureRef* texture_ref = GetTextureInfoForTargetUnlessDefault(target); + TextureRef* texture_ref = + texture_manager()->GetTextureInfoForTargetUnlessDefault(&state_, target); if (!texture_ref) { LOCAL_SET_GL_ERROR( GL_INVALID_OPERATION, @@ -9879,7 +9639,8 @@ void GLES2DecoderImpl::DoTexStorage2DEXT( GL_INVALID_VALUE, "glTexStorage2DEXT", "dimensions out of range"); return; } - TextureRef* texture_ref = GetTextureInfoForTarget(target); + TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget( + &state_, target); if (!texture_ref) { LOCAL_SET_GL_ERROR( GL_INVALID_OPERATION, @@ -9888,7 +9649,7 @@ void GLES2DecoderImpl::DoTexStorage2DEXT( } Texture* texture = texture_ref->texture(); if (texture->IsAttachedToFramebuffer()) { - clear_state_dirty_ = true; + framebuffer_state_.clear_state_dirty = true; } if (texture->IsImmutable()) { LOCAL_SET_GL_ERROR( @@ -9960,7 +9721,8 @@ void GLES2DecoderImpl::DoProduceTextureCHROMIUM(GLenum target, "context", logger_.GetLogPrefix(), "mailbox[0]", static_cast<unsigned char>(mailbox[0])); - TextureRef* texture_ref = GetTextureInfoForTarget(target); + TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget( + &state_, target); if (!texture_ref) { LOCAL_SET_GL_ERROR( GL_INVALID_OPERATION, @@ -9994,7 +9756,7 @@ void GLES2DecoderImpl::DoConsumeTextureCHROMIUM(GLenum target, "mailbox[0]", static_cast<unsigned char>(mailbox[0])); scoped_refptr<TextureRef> texture_ref = - GetTextureInfoForTargetUnlessDefault(target); + texture_manager()->GetTextureInfoForTargetUnlessDefault(&state_, target); if (!texture_ref.get()) { LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glConsumeTextureCHROMIUM", @@ -10085,7 +9847,8 @@ void GLES2DecoderImpl::DoBindTexImage2DCHROMIUM( // Default target might be conceptually valid, but disallow it to avoid // accidents. - TextureRef* texture_ref = GetTextureInfoForTargetUnlessDefault(target); + TextureRef* texture_ref = + texture_manager()->GetTextureInfoForTargetUnlessDefault(&state_, target); if (!texture_ref) { LOCAL_SET_GL_ERROR( GL_INVALID_OPERATION, @@ -10132,7 +9895,8 @@ void GLES2DecoderImpl::DoReleaseTexImage2DCHROMIUM( // Default target might be conceptually valid, but disallow it to avoid // accidents. - TextureRef* texture_ref = GetTextureInfoForTargetUnlessDefault(target); + TextureRef* texture_ref = + texture_manager()->GetTextureInfoForTargetUnlessDefault(&state_, target); if (!texture_ref) { LOCAL_SET_GL_ERROR( GL_INVALID_OPERATION, @@ -10273,7 +10037,9 @@ error::Error GLES2DecoderImpl::HandleAsyncTexImage2DCHROMIUM( TRACE_EVENT0("gpu", "GLES2DecoderImpl::HandleAsyncTexImage2DCHROMIUM"); GLenum target = static_cast<GLenum>(c.target); GLint level = static_cast<GLint>(c.level); - GLint internal_format = static_cast<GLint>(c.internalformat); + // 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); @@ -10299,15 +10065,17 @@ error::Error GLES2DecoderImpl::HandleAsyncTexImage2DCHROMIUM( } } + TextureManager::DoTextImage2DArguments args = { + target, level, internal_format, width, height, border, format, type, + pixels, pixels_size}; + TextureRef* texture_ref; // All the normal glTexSubImage2D validation. - if (!ValidateTexImage2D( - "glAsyncTexImage2DCHROMIUM", target, level, internal_format, - width, height, border, format, type, pixels, pixels_size)) { + if (!texture_manager()->ValidateTexImage2D( + &state_, "glAsyncTexImage2DCHROMIUM", args, &texture_ref)) { return error::kNoError; } // Extra async validation. - TextureRef* texture_ref = GetTextureInfoForTarget(target); Texture* texture = texture_ref->texture(); if (!ValidateAsyncTransfer( "glAsyncTexImage2DCHROMIUM", texture_ref, target, level, pixels)) @@ -10394,7 +10162,8 @@ error::Error GLES2DecoderImpl::HandleAsyncTexSubImage2DCHROMIUM( } // Extra async validation. - TextureRef* texture_ref = GetTextureInfoForTarget(target); + TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget( + &state_, target); Texture* texture = texture_ref->texture(); if (!ValidateAsyncTransfer( "glAsyncTexSubImage2DCHROMIUM", texture_ref, target, level, pixels)) @@ -10462,7 +10231,8 @@ error::Error GLES2DecoderImpl::HandleWaitAsyncTexImage2DCHROMIUM( GL_INVALID_ENUM, "glWaitAsyncTexImage2DCHROMIUM", "target"); return error::kNoError; } - TextureRef* texture_ref = GetTextureInfoForTarget(target); + TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget( + &state_, target); if (!texture_ref) { LOCAL_SET_GL_ERROR( GL_INVALID_OPERATION, diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h index a992e34..393c902 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h @@ -319,7 +319,7 @@ error::Error GLES2DecoderImpl::HandleColorMask( state_.color_mask_green = green; state_.color_mask_blue = blue; state_.color_mask_alpha = alpha; - clear_state_dirty_ = true; + framebuffer_state_.clear_state_dirty = true; } return error::kNoError; } @@ -678,7 +678,7 @@ error::Error GLES2DecoderImpl::HandleDepthMask( GLboolean flag = static_cast<GLboolean>(c.flag); if (state_.depth_mask != flag) { state_.depth_mask = flag; - clear_state_dirty_ = true; + framebuffer_state_.clear_state_dirty = true; } return error::kNoError; } @@ -1698,7 +1698,7 @@ error::Error GLES2DecoderImpl::HandleStencilMask( state_.stencil_back_writemask != mask) { state_.stencil_front_writemask = mask; state_.stencil_back_writemask = mask; - clear_state_dirty_ = true; + framebuffer_state_.clear_state_dirty = true; } return error::kNoError; } @@ -1725,7 +1725,7 @@ error::Error GLES2DecoderImpl::HandleStencilMaskSeparate( if (face == GL_BACK || face == GL_FRONT_AND_BACK) { state_.stencil_back_writemask = mask; } - clear_state_dirty_ = true; + framebuffer_state_.clear_state_dirty = true; } return error::kNoError; } @@ -3332,7 +3332,7 @@ bool GLES2DecoderImpl::SetCapabilityState(GLenum cap, bool enabled) { case GL_DEPTH_TEST: if (state_.enable_flags.depth_test != enabled) { state_.enable_flags.depth_test = enabled; - clear_state_dirty_ = true; + framebuffer_state_.clear_state_dirty = true; } return false; case GL_DITHER: @@ -3350,13 +3350,13 @@ bool GLES2DecoderImpl::SetCapabilityState(GLenum cap, bool enabled) { case GL_SCISSOR_TEST: if (state_.enable_flags.scissor_test != enabled) { state_.enable_flags.scissor_test = enabled; - clear_state_dirty_ = true; + framebuffer_state_.clear_state_dirty = true; } return false; case GL_STENCIL_TEST: if (state_.enable_flags.stencil_test != enabled) { state_.enable_flags.stencil_test = enabled; - clear_state_dirty_ = true; + framebuffer_state_.clear_state_dirty = true; } return false; default: diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc index 486bdac..deb8c8e 100644 --- a/gpu/command_buffer/service/texture_manager.cc +++ b/gpu/command_buffer/service/texture_manager.cc @@ -6,6 +6,7 @@ #include "base/bits.h" #include "base/strings/stringprintf.h" #include "gpu/command_buffer/common/gles2_cmd_utils.h" +#include "gpu/command_buffer/service/context_state.h" #include "gpu/command_buffer/service/error_state.h" #include "gpu/command_buffer/service/feature_info.h" #include "gpu/command_buffer/service/framebuffer_manager.h" @@ -1236,5 +1237,238 @@ void TextureManager::IncFramebufferStateChangeCount() { } +bool TextureManager::ValidateTextureParameters( + ErrorState* error_state, const char* function_name, + GLenum target, GLenum format, GLenum type, GLint level) { + if (!feature_info_->GetTextureFormatValidator(format).IsValid(type)) { + ERRORSTATE_SET_GL_ERROR( + error_state, GL_INVALID_OPERATION, function_name, + (std::string("invalid type ") + + GLES2Util::GetStringEnum(type) + " for format " + + GLES2Util::GetStringEnum(format)).c_str()); + return false; + } + + uint32 channels = GLES2Util::GetChannelsForFormat(format); + if ((channels & (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && level) { + ERRORSTATE_SET_GL_ERROR( + error_state, GL_INVALID_OPERATION, function_name, + (std::string("invalid type ") + + GLES2Util::GetStringEnum(type) + " for format " + + GLES2Util::GetStringEnum(format)).c_str()); + return false; + } + return true; +} + +// Gets the texture id for a given target. +TextureRef* TextureManager::GetTextureInfoForTarget( + ContextState* state, GLenum target) { + TextureUnit& unit = state->texture_units[state->active_texture_unit]; + TextureRef* texture = NULL; + switch (target) { + case GL_TEXTURE_2D: + texture = unit.bound_texture_2d.get(); + break; + case GL_TEXTURE_CUBE_MAP: + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + texture = unit.bound_texture_cube_map.get(); + break; + case GL_TEXTURE_EXTERNAL_OES: + texture = unit.bound_texture_external_oes.get(); + break; + case GL_TEXTURE_RECTANGLE_ARB: + texture = unit.bound_texture_rectangle_arb.get(); + break; + default: + NOTREACHED(); + return NULL; + } + return texture; +} + +TextureRef* TextureManager::GetTextureInfoForTargetUnlessDefault( + ContextState* state, GLenum target) { + TextureRef* texture = GetTextureInfoForTarget(state, target); + if (!texture) + return NULL; + if (texture == GetDefaultTextureInfo(target)) + return NULL; + return texture; +} + +bool TextureManager::ValidateTexImage2D( + ContextState* state, + const char* function_name, + const DoTextImage2DArguments& args, + TextureRef** texture_ref) { + ErrorState* error_state = state->GetErrorState(); + const Validators* validators = feature_info_->validators(); + if (!validators->texture_target.IsValid(args.target)) { + ERRORSTATE_SET_GL_ERROR_INVALID_ENUM( + error_state, function_name, args.target, "target"); + return false; + } + if (!validators->texture_format.IsValid(args.internal_format)) { + ERRORSTATE_SET_GL_ERROR_INVALID_ENUM( + error_state, function_name, args.internal_format, + "internal_format"); + return false; + } + if (!validators->texture_format.IsValid(args.format)) { + ERRORSTATE_SET_GL_ERROR_INVALID_ENUM( + error_state, function_name, args.format, "format"); + return false; + } + if (!validators->pixel_type.IsValid(args.type)) { + ERRORSTATE_SET_GL_ERROR_INVALID_ENUM( + error_state, function_name, args.type, "type"); + return false; + } + if (args.format != args.internal_format) { + ERRORSTATE_SET_GL_ERROR( + error_state, GL_INVALID_OPERATION, function_name, + "format != internalFormat"); + return false; + } + if (!ValidateTextureParameters( + error_state, function_name, args.target, args.format, args.type, + args.level)) { + return false; + } + if (!ValidForTarget(args.target, args.level, args.width, args.height, 1) || + args.border != 0) { + ERRORSTATE_SET_GL_ERROR( + error_state, GL_INVALID_VALUE, function_name, + "dimensions out of range"); + return false; + } + if ((GLES2Util::GetChannelsForFormat(args.format) & + (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && args.pixels) { + ERRORSTATE_SET_GL_ERROR( + error_state, GL_INVALID_OPERATION, + function_name, "can not supply data for depth or stencil textures"); + return false; + } + + TextureRef* local_texture_ref = GetTextureInfoForTarget(state, args.target); + if (!local_texture_ref) { + ERRORSTATE_SET_GL_ERROR( + error_state, GL_INVALID_OPERATION, function_name, + "unknown texture for target"); + return false; + } + if (local_texture_ref->texture()->IsImmutable()) { + ERRORSTATE_SET_GL_ERROR( + error_state, GL_INVALID_OPERATION, function_name, + "texture is immutable"); + return false; + } + + // TODO - verify that using the managed vs unmanaged does not matter. + // They both use the same MemoryTracker, and this call just re-routes + // to it. + if (!memory_tracker_managed_->EnsureGPUMemoryAvailable(args.pixels_size)) { + ERRORSTATE_SET_GL_ERROR(error_state, GL_OUT_OF_MEMORY, "glTexImage2D", + "out of memory"); + return false; + } + + // Write the TextureReference since this is valid. + *texture_ref = local_texture_ref; + return true; +} + +void TextureManager::ValidateAndDoTexImage2D( + DecoderTextureState* texture_state, + ContextState* state, + DecoderFramebufferState* framebuffer_state, + const DoTextImage2DArguments& args) { + TextureRef* texture_ref; + if (!ValidateTexImage2D(state, "glTexImage2D", args, &texture_ref)) { + return; + } + + DoTexImage2D(texture_state, state->GetErrorState(), framebuffer_state, + texture_ref, args); +} + +void TextureManager::DoTexImage2D( + DecoderTextureState* texture_state, + ErrorState* error_state, + DecoderFramebufferState* framebuffer_state, + TextureRef* texture_ref, + const DoTextImage2DArguments& args) { + Texture* texture = texture_ref->texture(); + GLsizei tex_width = 0; + GLsizei tex_height = 0; + GLenum tex_type = 0; + GLenum tex_format = 0; + bool level_is_same = + texture->GetLevelSize(args.target, args.level, &tex_width, &tex_height) && + texture->GetLevelType(args.target, args.level, &tex_type, &tex_format) && + args.width == tex_width && args.height == tex_height && + args.type == tex_type && args.format == tex_format; + + if (level_is_same && !args.pixels) { + // Just set the level texture but mark the texture as uncleared. + SetLevelInfo( + texture_ref, + args.target, args.level, args.internal_format, args.width, args.height, + 1, args.border, args.format, args.type, false); + texture_state->tex_image_2d_failed = false; + return; + } + + if (texture->IsAttachedToFramebuffer()) { + framebuffer_state->clear_state_dirty = true; + } + + if (!texture_state->teximage2d_faster_than_texsubimage2d && + level_is_same && args.pixels) { + { + ScopedTextureUploadTimer timer(texture_state); + glTexSubImage2D(args.target, args.level, 0, 0, args.width, args.height, + args.format, args.type, args.pixels); + } + SetLevelCleared(texture_ref, args.target, args.level, true); + texture_state->tex_image_2d_failed = false; + return; + } + + ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state, "glTexImage2D"); + { + ScopedTextureUploadTimer timer(texture_state); + glTexImage2D( + args.target, args.level, args.internal_format, args.width, args.height, + args.border, args.format, args.type, args.pixels); + } + GLenum error = ERRORSTATE_PEEK_GL_ERROR(error_state, "glTexImage2D"); + if (error == GL_NO_ERROR) { + SetLevelInfo( + texture_ref, + args.target, args.level, args.internal_format, args.width, args.height, + 1, args.border, args.format, args.type, args.pixels != NULL); + texture_state->tex_image_2d_failed = false; + } +} + +ScopedTextureUploadTimer::ScopedTextureUploadTimer( + DecoderTextureState* texture_state) + : texture_state_(texture_state), + begin_time_(base::TimeTicks::HighResNow()) { +} + +ScopedTextureUploadTimer::~ScopedTextureUploadTimer() { + texture_state_->texture_upload_count++; + texture_state_->total_texture_upload_time += + base::TimeTicks::HighResNow() - begin_time_; +} + } // namespace gles2 } // namespace gpu diff --git a/gpu/command_buffer/service/texture_manager.h b/gpu/command_buffer/service/texture_manager.h index cbc659c..db47004 100644 --- a/gpu/command_buffer/service/texture_manager.h +++ b/gpu/command_buffer/service/texture_manager.h @@ -27,6 +27,8 @@ class StreamTextureManager; namespace gles2 { class GLES2Decoder; +struct ContextState; +struct DecoderFramebufferState; class Display; class ErrorState; class FeatureInfo; @@ -429,6 +431,29 @@ class GPU_EXPORT TextureRef : public base::RefCounted<TextureRef> { DISALLOW_COPY_AND_ASSIGN(TextureRef); }; +// Holds data that is per gles2_cmd_decoder, but is related to to the +// TextureManager. +struct DecoderTextureState { + // total_texture_upload_time automatically initialized to 0 in default + // constructor. + DecoderTextureState(): + tex_image_2d_failed(false), + texture_upload_count(0), + teximage2d_faster_than_texsubimage2d(true) {} + + // This indicates all the following texSubImage2D calls that are part of the + // failed texImage2D call should be ignored. + bool tex_image_2d_failed; + + // Command buffer stats. + int texture_upload_count; + base::TimeDelta total_texture_upload_time; + + // This is really not per-decoder, but the logic to decide this value is in + // the decoder for now, so it is simpler to leave it there. + bool teximage2d_faster_than_texsubimage2d; +}; + // This class keeps track of the textures and their sizes so we can do NPOT and // texture complete checking. // @@ -671,6 +696,43 @@ class GPU_EXPORT TextureManager { destruction_observers_.RemoveObserver(observer); } + struct DoTextImage2DArguments { + GLenum target; + GLint level; + GLenum internal_format; + GLsizei width; + GLsizei height; + GLint border; + GLenum format; + GLenum type; + const void* pixels; + uint32 pixels_size; + }; + + bool ValidateTexImage2D( + ContextState* state, + const char* function_name, + const DoTextImage2DArguments& args, + // Pointer to TextureRef filled in if validation successful. + // Presumes the pointer is valid. + TextureRef** texture_ref); + + void ValidateAndDoTexImage2D( + DecoderTextureState* texture_state, + ContextState* state, + DecoderFramebufferState* framebuffer_state, + const DoTextImage2DArguments& args); + + // TODO(kloveless): Make GetTexture* private once this is no longer called + // from gles2_cmd_decoder. + TextureRef* GetTextureInfoForTarget(ContextState* state, GLenum target); + TextureRef* GetTextureInfoForTargetUnlessDefault( + ContextState* state, GLenum target); + + bool ValidateTextureParameters( + ErrorState* error_state, const char* function_name, + GLenum target, GLenum format, GLenum type, GLint level); + private: friend class Texture; friend class TextureRef; @@ -680,6 +742,13 @@ class GPU_EXPORT TextureManager { GLenum target, GLuint* black_texture); + void DoTexImage2D( + DecoderTextureState* texture_state, + ErrorState* error_state, + DecoderFramebufferState* framebuffer_state, + TextureRef* texture_ref, + const DoTextImage2DArguments& args); + void StartTracking(TextureRef* texture); void StopTracking(TextureRef* texture); @@ -730,6 +799,18 @@ class GPU_EXPORT TextureManager { DISALLOW_COPY_AND_ASSIGN(TextureManager); }; +// This class records texture upload time when in scope. +class ScopedTextureUploadTimer { + public: + explicit ScopedTextureUploadTimer(DecoderTextureState* texture_state); + ~ScopedTextureUploadTimer(); + + private: + DecoderTextureState* texture_state_; + base::TimeTicks begin_time_; + DISALLOW_COPY_AND_ASSIGN(ScopedTextureUploadTimer); +}; + } // namespace gles2 } // namespace gpu |