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 c525908a1f14913df300d49dfcacb0073f1bd710..2c22ae0dfb98ec1ee6700452d3d116141a7b7e3e 100644 |
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc |
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc |
@@ -353,9 +353,6 @@ class FrameBuffer { |
// currently bound frame buffer. |
void AttachRenderBuffer(GLenum target, RenderBuffer* render_buffer); |
- // Clear the given attached buffers. |
- void Clear(GLbitfield buffers); |
- |
// Destroy the frame buffer. This must be explicitly called before destroying |
// this object. |
void Destroy(); |
@@ -512,6 +509,7 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, |
virtual gfx::GLSurface* GetGLSurface() { return surface_.get(); } |
virtual ContextGroup* GetContextGroup() { return group_.get(); } |
+ virtual void SetGLError(GLenum error, const char* msg); |
virtual void SetResizeCallback(Callback1<gfx::Size>::Type* callback); |
#if defined(OS_MACOSX) |
@@ -844,10 +842,29 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, |
error::Error ShaderSourceHelper( |
GLuint client_id, const char* data, uint32 data_size); |
- // Clears any uncleared render buffers attached to the given frame buffer. |
- void ClearUnclearedRenderbuffers( |
+ // Clear any textures used by the current program. |
+ bool ClearUnclearedTextures(); |
+ |
+ // Clear any uncleared level in texture. |
+ // Returns false if there was a generated GL error. |
+ bool ClearTexture(TextureManager::TextureInfo* info); |
+ |
+ // Clears any uncleared attachments attached to the given frame buffer. |
+ // Returns false if there was a generated GL error. |
+ void ClearUnclearedAttachments( |
GLenum target, FramebufferManager::FramebufferInfo* info); |
+ // overridden from GLES2Decoder |
+ virtual bool ClearLevel( |
+ unsigned service_id, |
+ unsigned bind_target, |
+ unsigned target, |
+ int level, |
+ unsigned format, |
+ unsigned type, |
+ int width, |
+ int height); |
+ |
// Restore all GL state that affects clearing. |
void RestoreClearState(); |
@@ -855,8 +872,15 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, |
// Returns: true if glEnable/glDisable should actually be called. |
bool SetCapabilityState(GLenum cap, bool enabled); |
- // Check that the current frame buffer is complete. Generates error if not. |
- bool CheckFramebufferComplete(const char* func_name); |
+ // Check that the currently bound framebuffers are valid. |
+ // Generates GL error if not. |
+ bool CheckBoundFramebuffersValid(const char* func_name); |
+ |
+ // Check if a framebuffer meets our requirements. |
+ bool CheckFramebufferValid( |
+ FramebufferManager::FramebufferInfo* framebuffer, |
+ GLenum target, |
+ const char* func_name); |
// Checks if the current program exists and is valid. If not generates the |
// appropriate GL error. Returns true if the current program is in a usable |
@@ -1088,9 +1112,6 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, |
// this lets us peek at the error without losing it. |
GLenum PeekGLError(); |
- // Sets our wrapper for the GLError. |
- void SetGLError(GLenum error, const char* msg); |
- |
// Copies the real GL errors to the wrapper. This is so we can |
// make sure there are no native GL errors before calling some GL function |
// so that on return we know any error generated was for that specific |
@@ -1183,6 +1204,20 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, |
return (info && !info->IsDeleted()) ? info : NULL; |
} |
+ RenderbufferManager::RenderbufferInfo* GetRenderbufferInfoForTarget( |
+ GLenum target) { |
+ RenderbufferManager::RenderbufferInfo* info = NULL; |
+ switch (target) { |
+ case GL_RENDERBUFFER: |
+ info = bound_renderbuffer_; |
+ break; |
+ default: |
+ NOTREACHED(); |
+ break; |
+ } |
+ return (info && !info->IsDeleted()) ? info : NULL; |
+ } |
+ |
// Validates the program and location for a glGetUniform call and returns |
// a SizeResult setup to receive the result. Returns true if glGetUniform |
// should be called. |
@@ -1666,12 +1701,6 @@ void FrameBuffer::AttachRenderBuffer(GLenum target, |
attach_id); |
} |
-void FrameBuffer::Clear(GLbitfield buffers) { |
- ScopedGLErrorSuppressor suppressor(decoder_); |
- ScopedFrameBufferBinder binder(decoder_, id_); |
- glClear(buffers); |
-} |
- |
void FrameBuffer::Destroy() { |
if (id_ != 0) { |
ScopedGLErrorSuppressor suppressor(decoder_); |
@@ -2224,9 +2253,10 @@ bool GLES2DecoderImpl::MakeCurrent() { |
} |
void GLES2DecoderImpl::RestoreCurrentRenderbufferBindings() { |
+ RenderbufferManager::RenderbufferInfo* renderbuffer = |
+ GetRenderbufferInfoForTarget(GL_RENDERBUFFER); |
glBindRenderbufferEXT( |
- GL_RENDERBUFFER, |
- bound_renderbuffer_ ? bound_renderbuffer_->service_id() : 0); |
+ GL_RENDERBUFFER, renderbuffer ? renderbuffer->service_id() : 0); |
} |
static void RebindCurrentFramebuffer( |
@@ -2275,19 +2305,59 @@ void GLES2DecoderImpl::RestoreCurrentTexture2DBindings() { |
glActiveTexture(GL_TEXTURE0 + active_texture_unit_); |
} |
-bool GLES2DecoderImpl::CheckFramebufferComplete(const char* func_name) { |
- if (bound_draw_framebuffer_ && bound_draw_framebuffer_->IsNotComplete()) { |
- SetGLError(GL_INVALID_FRAMEBUFFER_OPERATION, |
- (std::string(func_name) + " framebuffer incomplete").c_str()); |
+bool GLES2DecoderImpl::CheckFramebufferValid( |
+ FramebufferManager::FramebufferInfo* framebuffer, |
+ GLenum target, const char* func_name) { |
+ if (!framebuffer || framebuffer->IsDeleted()) { |
+ return true; |
+ } |
+ |
+ GLenum completeness = framebuffer->IsPossiblyComplete(); |
+ if (completeness != GL_FRAMEBUFFER_COMPLETE) { |
+ SetGLError( |
+ GL_INVALID_FRAMEBUFFER_OPERATION, |
+ (std::string(func_name) + " framebuffer incomplete").c_str()); |
return false; |
} |
+ |
+ // Are all the attachments cleared? |
+ if (renderbuffer_manager()->HaveUnclearedRenderbuffers() || |
+ texture_manager()->HaveUnclearedMips()) { |
+ if (!framebuffer->IsCleared()) { |
+ // Can we clear them? |
+ if (glCheckFramebufferStatusEXT(target) != GL_FRAMEBUFFER_COMPLETE) { |
+ SetGLError( |
+ GL_INVALID_FRAMEBUFFER_OPERATION, |
+ (std::string(func_name) + |
+ " framebuffer incomplete (clear)").c_str()); |
+ return false; |
+ } |
+ ClearUnclearedAttachments(target, framebuffer); |
+ } |
+ } |
+ |
+ // NOTE: At this point we don't know if the framebuffer is complete but |
+ // we DO know that everything that needs to be cleared has been cleared. |
return true; |
} |
+bool GLES2DecoderImpl::CheckBoundFramebuffersValid(const char* func_name) { |
+ if (!feature_info_->feature_flags().chromium_framebuffer_multisample) { |
+ return CheckFramebufferValid( |
+ bound_draw_framebuffer_, GL_FRAMEBUFFER_EXT, func_name); |
+ } |
+ return CheckFramebufferValid( |
+ bound_draw_framebuffer_, GL_DRAW_FRAMEBUFFER_EXT, func_name) && |
+ CheckFramebufferValid( |
+ bound_read_framebuffer_, GL_READ_FRAMEBUFFER_EXT, func_name); |
+} |
+ |
gfx::Size GLES2DecoderImpl::GetBoundReadFrameBufferSize() { |
- if (bound_read_framebuffer_ != 0) { |
+ FramebufferManager::FramebufferInfo* framebuffer = |
+ GetFramebufferInfoForTarget(GL_READ_FRAMEBUFFER); |
+ if (framebuffer != NULL) { |
const FramebufferManager::FramebufferInfo::Attachment* attachment = |
- bound_read_framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0); |
+ framebuffer->GetAttachment(GL_COLOR_ATTACHMENT0); |
if (attachment) { |
return gfx::Size(attachment->width(), attachment->height()); |
} |
@@ -2300,8 +2370,10 @@ gfx::Size GLES2DecoderImpl::GetBoundReadFrameBufferSize() { |
} |
GLenum GLES2DecoderImpl::GetBoundReadFrameBufferInternalFormat() { |
- if (bound_read_framebuffer_ != 0) { |
- return bound_read_framebuffer_->GetColorAttachmentFormat(); |
+ FramebufferManager::FramebufferInfo* framebuffer = |
+ GetFramebufferInfoForTarget(GL_READ_FRAMEBUFFER); |
+ if (framebuffer != NULL) { |
+ return framebuffer->GetColorAttachmentFormat(); |
} else if (offscreen_target_frame_buffer_.get()) { |
return offscreen_target_color_format_; |
} else { |
@@ -2310,8 +2382,10 @@ GLenum GLES2DecoderImpl::GetBoundReadFrameBufferInternalFormat() { |
} |
GLenum GLES2DecoderImpl::GetBoundDrawFrameBufferInternalFormat() { |
- if (bound_draw_framebuffer_ != 0) { |
- return bound_draw_framebuffer_->GetColorAttachmentFormat(); |
+ FramebufferManager::FramebufferInfo* framebuffer = |
+ GetFramebufferInfoForTarget(GL_DRAW_FRAMEBUFFER); |
+ if (framebuffer != NULL) { |
+ return framebuffer->GetColorAttachmentFormat(); |
} else if (offscreen_target_frame_buffer_.get()) { |
return offscreen_target_color_format_; |
} else { |
@@ -2342,7 +2416,8 @@ void GLES2DecoderImpl::UpdateParentTextureInfo() { |
1, // depth |
0, // border |
GL_RGBA, |
- GL_UNSIGNED_BYTE); |
+ GL_UNSIGNED_BYTE, |
+ true); |
parent_texture_manager->SetParameter( |
feature_info_, |
info, |
@@ -2803,8 +2878,10 @@ bool GLES2DecoderImpl::BoundFramebufferHasColorAttachmentWithAlpha() { |
} |
bool GLES2DecoderImpl::BoundFramebufferHasDepthAttachment() { |
- if (bound_draw_framebuffer_) { |
- return bound_draw_framebuffer_->HasDepthAttachment(); |
+ FramebufferManager::FramebufferInfo* framebuffer = |
+ GetFramebufferInfoForTarget(GL_DRAW_FRAMEBUFFER); |
+ if (framebuffer) { |
+ return framebuffer->HasDepthAttachment(); |
} |
if (offscreen_target_frame_buffer_.get()) { |
return offscreen_target_depth_format_ != 0; |
@@ -2813,8 +2890,10 @@ bool GLES2DecoderImpl::BoundFramebufferHasDepthAttachment() { |
} |
bool GLES2DecoderImpl::BoundFramebufferHasStencilAttachment() { |
- if (bound_draw_framebuffer_) { |
- return bound_draw_framebuffer_->HasStencilAttachment(); |
+ FramebufferManager::FramebufferInfo* framebuffer = |
+ GetFramebufferInfoForTarget(GL_DRAW_FRAMEBUFFER); |
+ if (framebuffer) { |
+ return framebuffer->HasStencilAttachment(); |
} |
if (offscreen_target_frame_buffer_.get()) { |
return offscreen_target_stencil_format_ != 0 || |
@@ -3217,10 +3296,12 @@ bool GLES2DecoderImpl::GetHelper( |
// case GL_DRAW_FRAMEBUFFER_BINDING_EXT: (same as GL_FRAMEBUFFER_BINDING) |
*num_written = 1; |
if (params) { |
- if (bound_draw_framebuffer_) { |
+ FramebufferManager::FramebufferInfo* framebuffer = |
+ GetFramebufferInfoForTarget(GL_DRAW_FRAMEBUFFER); |
+ if (framebuffer) { |
GLuint client_id = 0; |
framebuffer_manager()->GetClientId( |
- bound_draw_framebuffer_->service_id(), &client_id); |
+ framebuffer->service_id(), &client_id); |
*params = client_id; |
} else { |
*params = 0; |
@@ -3230,10 +3311,12 @@ bool GLES2DecoderImpl::GetHelper( |
case GL_READ_FRAMEBUFFER_BINDING: |
*num_written = 1; |
if (params) { |
- if (bound_read_framebuffer_) { |
+ FramebufferManager::FramebufferInfo* framebuffer = |
+ GetFramebufferInfoForTarget(GL_READ_FRAMEBUFFER); |
+ if (framebuffer) { |
GLuint client_id = 0; |
framebuffer_manager()->GetClientId( |
- bound_read_framebuffer_->service_id(), &client_id); |
+ framebuffer->service_id(), &client_id); |
*params = client_id; |
} else { |
*params = 0; |
@@ -3243,10 +3326,12 @@ bool GLES2DecoderImpl::GetHelper( |
case GL_RENDERBUFFER_BINDING: |
*num_written = 1; |
if (params) { |
- if (bound_renderbuffer_) { |
+ RenderbufferManager::RenderbufferInfo* renderbuffer = |
+ GetRenderbufferInfoForTarget(GL_RENDERBUFFER); |
+ if (renderbuffer) { |
GLuint client_id = 0; |
renderbuffer_manager()->GetClientId( |
- bound_renderbuffer_->service_id(), &client_id); |
+ renderbuffer->service_id(), &client_id); |
*params = client_id; |
} else { |
*params = 0; |
@@ -3564,7 +3649,7 @@ error::Error GLES2DecoderImpl::HandleRegisterSharedIdsCHROMIUM( |
} |
void GLES2DecoderImpl::DoClear(GLbitfield mask) { |
- if (CheckFramebufferComplete("glClear")) { |
+ if (CheckBoundFramebuffersValid("glClear")) { |
ApplyDirtyState(); |
glClear(mask); |
} |
@@ -3597,12 +3682,6 @@ void GLES2DecoderImpl::DoFramebufferRenderbuffer( |
GLenum error = PeekGLError(); |
if (error == GL_NO_ERROR) { |
framebuffer_info->AttachRenderbuffer(attachment, info); |
- if (service_id == 0 || |
- glCheckFramebufferStatusEXT(target) == GL_FRAMEBUFFER_COMPLETE) { |
- if (info) { |
- ClearUnclearedRenderbuffers(target, framebuffer_info); |
- } |
- } |
} |
if (framebuffer_info == bound_draw_framebuffer_) { |
state_dirty_ = true; |
@@ -3693,20 +3772,24 @@ void GLES2DecoderImpl::DoStencilMaskSeparate(GLenum face, GLuint mask) { |
state_dirty_ = true; |
} |
-// NOTE: There's an assumption here that Texture attachments |
-// are cleared because they are textures so we only need to clear |
-// the renderbuffers. |
-void GLES2DecoderImpl::ClearUnclearedRenderbuffers( |
+// Assumes framebuffer is complete. |
+void GLES2DecoderImpl::ClearUnclearedAttachments( |
GLenum target, FramebufferManager::FramebufferInfo* info) { |
+ DCHECK(!info->IsDeleted()); |
if (target == GL_READ_FRAMEBUFFER_EXT) { |
- // TODO(gman): bind this to the DRAW point, clear then bind back to READ |
+ // bind this to the DRAW point, clear then bind back to READ |
+ // TODO(gman): I don't think there is any guarantee that an FBO that |
+ // is complete on the READ attachment will be complete as a DRAW |
+ // attachment. |
+ glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); |
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, info->service_id()); |
} |
GLbitfield clear_bits = 0; |
if (info->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)) { |
glClearColor( |
- 0, 0, 0, |
+ 0.0f, 0.0f, 0.0f, |
(GLES2Util::GetChannelsForFormat( |
- info->GetColorAttachmentFormat()) & 0x0008) != 0 ? 0 : 1); |
+ info->GetColorAttachmentFormat()) & 0x0008) != 0 ? 0.0f : 1.0f); |
glColorMask(true, true, true, true); |
clear_bits |= GL_COLOR_BUFFER_BIT; |
} |
@@ -3728,12 +3811,16 @@ void GLES2DecoderImpl::ClearUnclearedRenderbuffers( |
glDisable(GL_SCISSOR_TEST); |
glClear(clear_bits); |
- info->MarkAttachedRenderbuffersAsCleared(); |
+ info->MarkAttachmentsAsCleared(renderbuffer_manager(), texture_manager()); |
RestoreClearState(); |
if (target == GL_READ_FRAMEBUFFER_EXT) { |
- // TODO(gman): rebind draw. |
+ glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, info->service_id()); |
+ FramebufferManager::FramebufferInfo*framebuffer = |
+ GetFramebufferInfoForTarget(GL_READ_FRAMEBUFFER); |
+ glBindFramebufferEXT( |
+ GL_DRAW_FRAMEBUFFER_EXT, framebuffer ? framebuffer->service_id() : 0); |
} |
} |
@@ -3748,11 +3835,15 @@ void GLES2DecoderImpl::RestoreClearState() { |
} |
GLenum GLES2DecoderImpl::DoCheckFramebufferStatus(GLenum target) { |
- FramebufferManager::FramebufferInfo* info = |
+ FramebufferManager::FramebufferInfo* framebuffer = |
GetFramebufferInfoForTarget(target); |
- if (!info) { |
+ if (!framebuffer) { |
return GL_FRAMEBUFFER_COMPLETE; |
} |
+ GLenum completeness = framebuffer->IsPossiblyComplete(); |
+ if (completeness != GL_FRAMEBUFFER_COMPLETE) { |
+ return completeness; |
+ } |
return glCheckFramebufferStatusEXT(target); |
} |
@@ -3777,15 +3868,19 @@ void GLES2DecoderImpl::DoFramebufferTexture2D( |
} |
service_id = info->service_id(); |
} |
+ |
+ if (!texture_manager()->ValidForTarget( |
+ feature_info_, textarget, level, 0, 0, 1)) { |
+ SetGLError(GL_INVALID_VALUE, |
+ "glFramebufferTexture2D: level out of range"); |
+ return; |
+ } |
+ |
CopyRealGLErrorsToWrapper(); |
glFramebufferTexture2DEXT(target, attachment, textarget, service_id, level); |
GLenum error = PeekGLError(); |
if (error == GL_NO_ERROR) { |
framebuffer_info->AttachTexture(attachment, info, textarget, level); |
- if (service_id != 0 && |
- glCheckFramebufferStatusEXT(target) == GL_FRAMEBUFFER_COMPLETE) { |
- ClearUnclearedRenderbuffers(target, framebuffer_info); |
- } |
} |
if (framebuffer_info == bound_draw_framebuffer_) { |
state_dirty_ = true; |
@@ -3825,20 +3920,22 @@ void GLES2DecoderImpl::DoGetFramebufferAttachmentParameteriv( |
void GLES2DecoderImpl::DoGetRenderbufferParameteriv( |
GLenum target, GLenum pname, GLint* params) { |
- if (!bound_renderbuffer_) { |
+ RenderbufferManager::RenderbufferInfo* renderbuffer = |
+ GetRenderbufferInfoForTarget(GL_RENDERBUFFER); |
+ if (!renderbuffer) { |
SetGLError(GL_INVALID_OPERATION, |
"glGetRenderbufferParameteriv: no renderbuffer bound"); |
return; |
} |
switch (pname) { |
case GL_RENDERBUFFER_INTERNAL_FORMAT: |
- *params = bound_renderbuffer_->internal_format(); |
+ *params = renderbuffer->internal_format(); |
break; |
case GL_RENDERBUFFER_WIDTH: |
- *params = bound_renderbuffer_->width(); |
+ *params = renderbuffer->width(); |
break; |
case GL_RENDERBUFFER_HEIGHT: |
- *params = bound_renderbuffer_->height(); |
+ *params = renderbuffer->height(); |
break; |
default: |
glGetRenderbufferParameterivEXT(target, pname, params); |
@@ -3872,6 +3969,14 @@ void GLES2DecoderImpl::DoRenderbufferStorageMultisample( |
return; |
} |
+ RenderbufferManager::RenderbufferInfo* renderbuffer = |
+ GetRenderbufferInfoForTarget(GL_RENDERBUFFER); |
+ if (!renderbuffer) { |
+ SetGLError(GL_INVALID_OPERATION, |
+ "glGetRenderbufferStorageMultisample: no renderbuffer bound"); |
+ return; |
+ } |
+ |
if (samples > renderbuffer_manager()->max_samples()) { |
SetGLError(GL_INVALID_VALUE, |
"glGetRenderbufferStorageMultisample: samples too large"); |
@@ -3911,13 +4016,16 @@ void GLES2DecoderImpl::DoRenderbufferStorageMultisample( |
} |
GLenum error = PeekGLError(); |
if (error == GL_NO_ERROR) { |
- bound_renderbuffer_->SetInfo(samples, internalformat, width, height); |
+ renderbuffer_manager()->SetInfo( |
+ renderbuffer, samples, internalformat, width, height); |
} |
} |
void GLES2DecoderImpl::DoRenderbufferStorage( |
GLenum target, GLenum internalformat, GLsizei width, GLsizei height) { |
- if (!bound_renderbuffer_) { |
+ RenderbufferManager::RenderbufferInfo* renderbuffer = |
+ GetRenderbufferInfoForTarget(GL_RENDERBUFFER); |
+ if (!renderbuffer) { |
SetGLError(GL_INVALID_OPERATION, |
"glGetRenderbufferStorage: no renderbuffer bound"); |
return; |
@@ -3950,7 +4058,8 @@ void GLES2DecoderImpl::DoRenderbufferStorage( |
glRenderbufferStorageEXT(target, impl_format, width, height); |
GLenum error = PeekGLError(); |
if (error == GL_NO_ERROR) { |
- bound_renderbuffer_->SetInfo(0, internalformat, width, height); |
+ renderbuffer_manager()->SetInfo( |
+ renderbuffer, 0, internalformat, width, height); |
} |
} |
@@ -4370,6 +4479,38 @@ void GLES2DecoderImpl::RestoreStateForNonRenderableTextures() { |
glActiveTexture(GL_TEXTURE0 + active_texture_unit_); |
} |
+bool GLES2DecoderImpl::ClearUnclearedTextures() { |
+ // Only check if there are some uncleared textures. |
+ if (!texture_manager()->HaveUnsafeTextures()) { |
+ return true; |
+ } |
+ |
+ // 1: Check all textures we are about to render with. |
+ if (current_program_) { |
+ const ProgramManager::ProgramInfo::SamplerIndices& sampler_indices = |
+ current_program_->sampler_indices(); |
+ for (size_t ii = 0; ii < sampler_indices.size(); ++ii) { |
+ const ProgramManager::ProgramInfo::UniformInfo* uniform_info = |
+ current_program_->GetUniformInfo(sampler_indices[ii]); |
+ DCHECK(uniform_info); |
+ for (size_t jj = 0; jj < uniform_info->texture_units.size(); ++jj) { |
+ GLuint texture_unit_index = uniform_info->texture_units[jj]; |
+ if (texture_unit_index < group_->max_texture_units()) { |
+ TextureUnit& texture_unit = texture_units_[texture_unit_index]; |
+ TextureManager::TextureInfo* texture_info = |
+ texture_unit.GetInfoForSamplerType(uniform_info->type); |
+ if (texture_info && !texture_info->SafeToRenderFrom()) { |
+ if (!texture_manager()->ClearRenderableLevels(this, texture_info)) { |
+ return false; |
+ } |
+ } |
+ } |
+ } |
+ } |
+ } |
+ return true; |
+} |
+ |
bool GLES2DecoderImpl::IsDrawValid(GLuint max_vertex_accessed) { |
// NOTE: We specifically do not check current_program->IsValid() because |
// it could never be invalid since glUseProgram would have failed. While |
@@ -4604,7 +4745,7 @@ error::Error GLES2DecoderImpl::HandleDrawArrays( |
SetGLError(GL_INVALID_VALUE, "glDrawArrays: count < 0"); |
return error::kNoError; |
} |
- if (!CheckFramebufferComplete("glDrawArrays")) { |
+ if (!CheckBoundFramebuffersValid("glDrawArrays")) { |
return error::kNoError; |
} |
// We have to check this here because the prototype for glDrawArrays |
@@ -4620,6 +4761,10 @@ error::Error GLES2DecoderImpl::HandleDrawArrays( |
GLuint max_vertex_accessed = first + count - 1; |
if (IsDrawValid(max_vertex_accessed)) { |
+ if (!ClearUnclearedTextures()) { |
+ SetGLError(GL_INVALID_VALUE, "glDrawArrays: out of memory"); |
+ return error::kNoError; |
+ } |
bool simulated_attrib_0 = false; |
if (!SimulateAttrib0(max_vertex_accessed, &simulated_attrib_0)) { |
return error::kNoError; |
@@ -4677,7 +4822,7 @@ error::Error GLES2DecoderImpl::HandleDrawElements( |
return error::kNoError; |
} |
- if (!CheckFramebufferComplete("glDrawElements")) { |
+ if (!CheckBoundFramebuffersValid("glDrawElements")) { |
return error::kNoError; |
} |
@@ -4694,6 +4839,10 @@ error::Error GLES2DecoderImpl::HandleDrawElements( |
} |
if (IsDrawValid(max_vertex_accessed)) { |
+ if (!ClearUnclearedTextures()) { |
+ SetGLError(GL_INVALID_VALUE, "glDrawElements: out of memory"); |
+ return error::kNoError; |
+ } |
bool simulated_attrib_0 = false; |
if (!SimulateAttrib0(max_vertex_accessed, &simulated_attrib_0)) { |
return error::kNoError; |
@@ -5376,6 +5525,10 @@ error::Error GLES2DecoderImpl::HandleReadPixels( |
return error::kNoError; |
} |
+ if (!CheckBoundFramebuffersValid("glReadPixels")) { |
+ return error::kNoError; |
+ } |
+ |
if (x < 0 || y < 0 || max_x > max_size.width() || max_y > max_size.height()) { |
// The user requested an out of range area. Get the results 1 line |
// at a time. |
@@ -5791,6 +5944,31 @@ void GLES2DecoderImpl::DoBufferSubData( |
glBufferSubData(target, offset, size, data); |
} |
+bool GLES2DecoderImpl::ClearLevel( |
+ unsigned service_id, |
+ unsigned bind_target, |
+ unsigned target, |
+ int level, |
+ unsigned format, |
+ unsigned type, |
+ int width, |
+ int height) { |
+ // Assumes the size has already been checked. |
+ uint32 pixels_size = 0; |
+ if (!GLES2Util::ComputeImageDataSize( |
+ width, height, format, type, unpack_alignment_, &pixels_size)) { |
+ return false; |
+ } |
+ scoped_array<char> zero(new char[pixels_size]); |
+ memset(zero.get(), 0, pixels_size); |
+ glBindTexture(bind_target, service_id); |
+ WrappedTexImage2D( |
+ target, level, format, width, height, 0, format, type, zero.get()); |
+ TextureManager::TextureInfo* info = GetTextureInfoForTarget(bind_target); |
+ glBindTexture(bind_target, info ? info->service_id() : 0); |
+ return true; |
+} |
+ |
error::Error GLES2DecoderImpl::DoCompressedTexImage2D( |
GLenum target, |
GLint level, |
@@ -5838,7 +6016,8 @@ error::Error GLES2DecoderImpl::DoCompressedTexImage2D( |
if (error == GL_NO_ERROR) { |
texture_manager()->SetLevelInfo( |
feature_info_, |
- info, target, level, internal_format, width, height, 1, border, 0, 0); |
+ info, target, level, internal_format, width, height, 1, border, 0, 0, |
+ true); |
} |
return error::kNoError; |
} |
@@ -6014,13 +6193,6 @@ error::Error GLES2DecoderImpl::DoTexImage2D( |
return error::kNoError; |
} |
- scoped_array<int8> zero; |
- if (!pixels) { |
- zero.reset(new int8[pixels_size]); |
- memset(zero.get(), 0, pixels_size); |
- pixels = zero.get(); |
- } |
- |
if (info->IsAttachedToFramebuffer()) { |
state_dirty_ = true; |
} |
@@ -6037,8 +6209,10 @@ error::Error GLES2DecoderImpl::DoTexImage2D( |
pixels); |
GLenum error = PeekGLError(); |
if (error == GL_NO_ERROR) { |
- texture_manager()->SetLevelInfo(feature_info_, info, |
- target, level, internal_format, width, height, 1, border, format, type); |
+ texture_manager()->SetLevelInfo( |
+ feature_info_, info, |
+ target, level, internal_format, width, height, 1, border, format, type, |
+ pixels != NULL); |
tex_image_2d_failed_ = false; |
} |
return error::kNoError; |
@@ -6138,6 +6312,10 @@ void GLES2DecoderImpl::DoCompressedTexSubImage2D( |
"glCompressdTexSubImage2D: bad dimensions."); |
return; |
} |
+ // Note: There is no need to deal with texture cleared tracking here |
+ // because the validation above means you can only get here if the level |
+ // is already a matching compressed format and in that case |
+ // CompressedTexImage2D already cleared the texture. |
glCompressedTexSubImage2D( |
target, level, xoffset, yoffset, width, height, format, image_size, data); |
} |
@@ -6159,7 +6337,6 @@ static void Clip( |
*out_range = range; |
} |
- |
void GLES2DecoderImpl::DoCopyTexImage2D( |
GLenum target, |
GLint level, |
@@ -6213,17 +6390,12 @@ void GLES2DecoderImpl::DoCopyTexImage2D( |
copyWidth != width || |
copyHeight != height) { |
// some part was clipped so clear the texture. |
- uint32 pixels_size = 0; |
- if (!GLES2Util::ComputeImageDataSize( |
- width, height, internal_format, GL_UNSIGNED_BYTE, |
- unpack_alignment_, &pixels_size)) { |
- SetGLError(GL_INVALID_VALUE, "glCopyTexImage2D: dimensions too large"); |
+ if (!ClearLevel( |
+ info->service_id(), info->target(), |
+ target, level, internal_format, GL_UNSIGNED_BYTE, width, height)) { |
+ SetGLError(GL_OUT_OF_MEMORY, "glCopyTexImage2D: dimensions too big"); |
return; |
} |
- scoped_array<char> zero(new char[pixels_size]); |
- memset(zero.get(), 0, pixels_size); |
- glTexImage2D(target, level, internal_format, width, height, 0, |
- internal_format, GL_UNSIGNED_BYTE, zero.get()); |
if (copyHeight > 0 && copyWidth > 0) { |
GLint dx = copyX - x; |
GLint dy = copyY - y; |
@@ -6241,7 +6413,7 @@ void GLES2DecoderImpl::DoCopyTexImage2D( |
if (error == GL_NO_ERROR) { |
texture_manager()->SetLevelInfo( |
feature_info_, info, target, level, internal_format, width, height, 1, |
- border, internal_format, GL_UNSIGNED_BYTE); |
+ border, internal_format, GL_UNSIGNED_BYTE, true); |
} |
} |
@@ -6289,11 +6461,17 @@ void GLES2DecoderImpl::DoCopyTexSubImage2D( |
GLint copyHeight = 0; |
Clip(x, width, size.width(), ©X, ©Width); |
Clip(y, height, size.height(), ©Y, ©Height); |
+ |
+ if (!texture_manager()->ClearTextureLevel(this, info, target, level)) { |
+ SetGLError(GL_OUT_OF_MEMORY, "glCopyTexSubImage2D: dimensions too big"); |
+ return; |
+ } |
+ |
if (copyX != x || |
copyY != y || |
copyWidth != width || |
copyHeight != height) { |
- // some part was clipped so clear the texture. |
+ // some part was clipped so clear the sub rect. |
uint32 pixels_size = 0; |
if (!GLES2Util::ComputeImageDataSize( |
width, height, format, type, unpack_alignment_, &pixels_size)) { |
@@ -6306,6 +6484,7 @@ void GLES2DecoderImpl::DoCopyTexSubImage2D( |
target, level, xoffset, yoffset, width, height, |
format, type, zero.get()); |
} |
+ |
if (copyHeight > 0 && copyWidth > 0) { |
GLint dx = copyX - x; |
GLint dy = copyY - y; |
@@ -6370,9 +6549,14 @@ void GLES2DecoderImpl::DoTexSubImage2D( |
// same as internal_foramt. If that changes we'll need to look them up. |
WrappedTexImage2D( |
target, level, format, width, height, 0, format, type, data); |
+ texture_manager()->SetLevelCleared(info, target, level); |
return; |
} |
} |
+ if (!texture_manager()->ClearTextureLevel(this, info, target, level)) { |
+ SetGLError(GL_OUT_OF_MEMORY, "glTexSubImage2D: dimensions too big"); |
+ return; |
+ } |
glTexSubImage2D( |
target, level, xoffset, yoffset, width, height, format, type, data); |
} |