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 3e0e02ac6a65431059ab47b5bdd147e1a2727f38..e23c05b62168a511f162b28e10e04cb6481bace0 100644 |
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc |
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc |
@@ -126,7 +126,7 @@ static bool IsAngle() { |
#endif |
} |
-void WrappedTexImage2D( |
+static void WrappedTexImage2D( |
GLenum target, |
GLint level, |
GLenum internal_format, |
@@ -735,6 +735,15 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, |
void RestoreCurrentRenderbufferBindings(); |
void RestoreCurrentTexture2DBindings(); |
+ // Sets DEPTH_TEST, STENCIL_TEST and color mask for the current framebuffer. |
+ void ApplyDirtyState(); |
+ |
+ // These check the state of the currently bound framebuffer or the |
+ // backbuffer if no framebuffer is bound. |
+ bool BoundFramebufferHasColorAttachmentWithAlpha(); |
+ bool BoundFramebufferHasDepthAttachment(); |
+ bool BoundFramebufferHasStencilAttachment(); |
+ |
private: |
friend class ScopedGLErrorSuppressor; |
friend class ScopedResolvedFrameBufferBinder; |
@@ -824,6 +833,7 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, |
// Get the format of the currently bound frame buffer (either FBO or regular |
// back buffer) |
GLenum GetBoundReadFrameBufferInternalFormat(); |
+ GLenum GetBoundDrawFrameBufferInternalFormat(); |
// Wrapper for CompressedTexImage2D commands. |
error::Error DoCompressedTexImage2D( |
@@ -1259,8 +1269,8 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, |
// Wrapper for glValidateProgram. |
void DoValidateProgram(GLuint program_client_id); |
- void DoCopyTextureToParentTextureCHROMIUM(GLuint client_texture_id, |
- GLuint parent_client_texture_id); |
+ void DoCopyTextureToParentTextureCHROMIUM( |
+ GLuint client_texture_id, GLuint parent_client_texture_id); |
void DoResizeCHROMIUM(GLuint width, GLuint height); |
@@ -1462,6 +1472,7 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, |
GLclampf clear_depth_; |
GLboolean mask_depth_; |
bool enable_scissor_test_; |
+ bool state_dirty_; |
// The program in use by glUseProgram |
ProgramManager::ProgramInfo::Ref current_program_; |
@@ -1501,6 +1512,8 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>, |
// The format of the back buffer_ |
GLenum back_buffer_color_format_; |
+ bool back_buffer_has_depth_; |
+ bool back_buffer_has_stencil_; |
bool teximage2d_faster_than_texsubimage2d_; |
bool bufferdata_faster_than_buffersubdata_; |
@@ -1844,6 +1857,7 @@ GLES2DecoderImpl::GLES2DecoderImpl(SurfaceManager* surface_manager, |
clear_depth_(1.0f), |
mask_depth_(true), |
enable_scissor_test_(false), |
+ state_dirty_(true), |
offscreen_target_color_format_(0), |
offscreen_target_depth_format_(0), |
offscreen_target_stencil_format_(0), |
@@ -1851,6 +1865,8 @@ GLES2DecoderImpl::GLES2DecoderImpl(SurfaceManager* surface_manager, |
copy_texture_to_parent_texture_fb_(0), |
offscreen_saved_color_format_(0), |
back_buffer_color_format_(0), |
+ back_buffer_has_depth_(false), |
+ back_buffer_has_stencil_(false), |
teximage2d_faster_than_texsubimage2d_(true), |
bufferdata_faster_than_buffersubdata_(true), |
current_decoder_error_(error::kNoError), |
@@ -1930,10 +1946,6 @@ bool GLES2DecoderImpl::Initialize( |
vertex_attrib_manager_.Initialize(group_->max_vertex_attribs()); |
- GLint v = 0; |
- glGetIntegerv(GL_ALPHA_BITS, &v); |
- back_buffer_color_format_ = v ? GL_RGBA : GL_RGB; |
- |
if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) { |
// We have to enable vertex array 0 on OpenGL or it won't render. Note that |
// OpenGL ES 2.0 does not have this issue. |
@@ -1961,11 +1973,30 @@ bool GLES2DecoderImpl::Initialize( |
glActiveTexture(GL_TEXTURE0); |
CHECK_GL_ERROR(); |
- if (surface_->IsOffscreen()) { |
- ContextCreationAttribParser attrib_parser; |
- if (!attrib_parser.Parse(attribs)) |
- return false; |
+ ContextCreationAttribParser attrib_parser; |
+ if (!attrib_parser.Parse(attribs)) |
+ return false; |
+ |
+ // These are NOT if the back buffer has these proprorties. They are |
+ // if we want the command buffer to enforce them regardless of what |
+ // the real backbuffer is assuming the real back buffer gives us more than |
+ // we ask for. In other words, if we ask for RGB and we get RGBA then we'll |
+ // make it appear RGB. If on the other hand we ask for RGBA nd get RGB we |
+ // can't do anything about that. |
+ |
+ GLint v = 0; |
+ glGetIntegerv(GL_ALPHA_BITS, &v); |
+ // This checks if the user requested RGBA and we have RGBA then RGBA. If the |
+ // user requested RGB then RGB. If the user did not specify a preference than |
+ // use whatever we were given. Same for DEPTH and STENCIL. |
+ back_buffer_color_format_ = |
+ (attrib_parser.alpha_size_ != 0 && v > 0) ? GL_RGBA : GL_RGB; |
+ glGetIntegerv(GL_DEPTH_BITS, &v); |
+ back_buffer_has_depth_ = attrib_parser.depth_size_ != 0 && v > 0; |
+ glGetIntegerv(GL_STENCIL_BITS, &v); |
+ back_buffer_has_stencil_ = attrib_parser.stencil_size_ != 0 && v > 0; |
+ if (surface_->IsOffscreen()) { |
if (attrib_parser.samples_ > 0 && attrib_parser.sample_buffers_ > 0 && |
(context_->HasExtension("GL_EXT_framebuffer_multisample") || |
context_->HasExtension("GL_ANGLE_framebuffer_multisample"))) { |
@@ -2234,6 +2265,10 @@ void GLES2DecoderImpl::DeleteFramebuffersHelper( |
FramebufferManager::FramebufferInfo* info = |
GetFramebufferInfo(client_ids[ii]); |
if (info) { |
+ if (info == bound_draw_framebuffer_) { |
+ bound_draw_framebuffer_ = NULL; |
+ state_dirty_ = true; |
+ } |
GLuint service_id = info->service_id(); |
glDeleteFramebuffersEXT(1, &service_id); |
RemoveFramebufferInfo(client_ids[ii]); |
@@ -2247,6 +2282,7 @@ void GLES2DecoderImpl::DeleteRenderbuffersHelper( |
RenderbufferManager::RenderbufferInfo* info = |
GetRenderbufferInfo(client_ids[ii]); |
if (info) { |
+ state_dirty_ = true; |
GLuint service_id = info->service_id(); |
glDeleteRenderbuffersEXT(1, &service_id); |
RemoveRenderbufferInfo(client_ids[ii]); |
@@ -2259,6 +2295,9 @@ void GLES2DecoderImpl::DeleteTexturesHelper( |
for (GLsizei ii = 0; ii < n; ++ii) { |
TextureManager::TextureInfo* info = GetTextureInfo(client_ids[ii]); |
if (info) { |
+ if (info->IsAttachedToFramebuffer()) { |
+ state_dirty_ = true; |
+ } |
GLuint service_id = info->service_id(); |
glDeleteTextures(1, &service_id); |
RemoveTextureInfo(client_ids[ii]); |
@@ -2283,13 +2322,17 @@ static void RebindCurrentFramebuffer( |
FramebufferManager::FramebufferInfo* info, |
FrameBuffer* offscreen_frame_buffer) { |
GLuint framebuffer_id = info ? info->service_id() : 0; |
+ |
if (framebuffer_id == 0 && offscreen_frame_buffer) { |
framebuffer_id = offscreen_frame_buffer->id(); |
} |
+ |
glBindFramebufferEXT(target, framebuffer_id); |
} |
void GLES2DecoderImpl::RestoreCurrentFramebufferBindings() { |
+ state_dirty_ = true; |
+ |
if (!feature_info_->feature_flags().chromium_framebuffer_multisample) { |
RebindCurrentFramebuffer( |
GL_FRAMEBUFFER, |
@@ -2346,12 +2389,17 @@ gfx::Size GLES2DecoderImpl::GetBoundReadFrameBufferSize() { |
GLenum GLES2DecoderImpl::GetBoundReadFrameBufferInternalFormat() { |
if (bound_read_framebuffer_ != 0) { |
- const FramebufferManager::FramebufferInfo::Attachment* attachment = |
- bound_read_framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0); |
- if (attachment) { |
- return attachment->internal_format(); |
- } |
- return 0; |
+ return bound_read_framebuffer_->GetColorAttachmentFormat(); |
+ } else if (offscreen_target_frame_buffer_.get()) { |
+ return offscreen_target_color_format_; |
+ } else { |
+ return back_buffer_color_format_; |
+ } |
+} |
+ |
+GLenum GLES2DecoderImpl::GetBoundDrawFrameBufferInternalFormat() { |
+ if (bound_draw_framebuffer_ != 0) { |
+ return bound_draw_framebuffer_->GetColorAttachmentFormat(); |
} else if (offscreen_target_frame_buffer_.get()) { |
return offscreen_target_color_format_; |
} else { |
@@ -2443,7 +2491,7 @@ bool GLES2DecoderImpl::UpdateOffscreenFrameBufferSize() { |
// Clear the target frame buffer. |
{ |
ScopedFrameBufferBinder binder(this, offscreen_target_frame_buffer_->id()); |
- glClearColor(0, 0, 0, 0); |
+ glClearColor(0, 0, 0, offscreen_target_color_format_ == GL_RGB); |
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
glClearStencil(0); |
glStencilMaskSeparate(GL_FRONT, GL_TRUE); |
@@ -2824,6 +2872,47 @@ void GLES2DecoderImpl::DoBindBuffer(GLenum target, GLuint client_id) { |
glBindBuffer(target, service_id); |
} |
+bool GLES2DecoderImpl::BoundFramebufferHasColorAttachmentWithAlpha() { |
+ return (GLES2Util::GetChannelsForFormat( |
+ GetBoundDrawFrameBufferInternalFormat()) & 0x0008) != 0; |
+} |
+ |
+bool GLES2DecoderImpl::BoundFramebufferHasDepthAttachment() { |
+ if (bound_draw_framebuffer_) { |
+ return bound_draw_framebuffer_->HasDepthAttachment(); |
+ } |
+ if (offscreen_target_frame_buffer_.get()) { |
+ return offscreen_target_depth_format_ != 0; |
+ } |
+ return back_buffer_has_depth_; |
+} |
+ |
+bool GLES2DecoderImpl::BoundFramebufferHasStencilAttachment() { |
+ if (bound_draw_framebuffer_) { |
+ return bound_draw_framebuffer_->HasStencilAttachment(); |
+ } |
+ if (offscreen_target_frame_buffer_.get()) { |
+ return offscreen_target_stencil_format_ != 0; |
+ } |
+ return back_buffer_has_stencil_; |
+} |
+ |
+void GLES2DecoderImpl::ApplyDirtyState() { |
+ if (state_dirty_) { |
+ glColorMask( |
+ mask_red_, mask_green_, mask_blue_, |
+ mask_alpha_ && BoundFramebufferHasColorAttachmentWithAlpha()); |
+ glDepthMask(mask_depth_ && BoundFramebufferHasDepthAttachment()); |
+ glStencilMaskSeparate( |
+ GL_FRONT, |
+ BoundFramebufferHasStencilAttachment() ? mask_stencil_front_ : 0); |
+ glStencilMaskSeparate( |
+ GL_BACK, |
+ BoundFramebufferHasStencilAttachment() ? mask_stencil_back_ : 0); |
+ state_dirty_ = false; |
+ } |
+} |
+ |
void GLES2DecoderImpl::DoBindFramebuffer(GLenum target, GLuint client_id) { |
FramebufferManager::FramebufferInfo* info = NULL; |
GLuint service_id = 0; |
@@ -2852,10 +2941,13 @@ void GLES2DecoderImpl::DoBindFramebuffer(GLenum target, GLuint client_id) { |
bound_read_framebuffer_ = info; |
} |
+ state_dirty_ = true; |
+ |
// When rendering to an offscreen frame buffer, instead of unbinding from |
// the current frame buffer, bind to the offscreen target frame buffer. |
- if (info == NULL && offscreen_target_frame_buffer_.get()) |
+ if (info == NULL && offscreen_target_frame_buffer_.get()) { |
service_id = offscreen_target_frame_buffer_->id(); |
+ } |
glBindFramebufferEXT(target, service_id); |
} |
@@ -3009,6 +3101,57 @@ bool GLES2DecoderImpl::GetHelper( |
} |
} |
switch (pname) { |
+ case GL_COLOR_WRITEMASK: |
+ *num_written = 4; |
+ if (params) { |
+ params[0] = mask_red_; |
+ params[1] = mask_green_; |
+ params[2] = mask_blue_; |
+ params[3] = mask_alpha_; |
+ } |
+ return true; |
+ case GL_DEPTH_WRITEMASK: |
+ *num_written = 1; |
+ if (params) { |
+ params[0] = mask_depth_; |
+ } |
+ return true; |
+ case GL_STENCIL_BACK_WRITEMASK: |
+ *num_written = 1; |
+ if (params) { |
+ params[0] = mask_stencil_back_; |
+ } |
+ return true; |
+ case GL_STENCIL_WRITEMASK: |
+ *num_written = 1; |
+ if (params) { |
+ params[0] = mask_stencil_front_; |
+ } |
+ return true; |
+ case GL_ALPHA_BITS: |
+ *num_written = 1; |
+ if (params) { |
+ GLint v = 0; |
+ glGetIntegerv(GL_ALPHA_BITS, &v); |
+ params[0] = BoundFramebufferHasColorAttachmentWithAlpha() ? v : 0; |
+ } |
+ return true; |
+ case GL_DEPTH_BITS: |
+ *num_written = 1; |
+ if (params) { |
+ GLint v = 0; |
+ glGetIntegerv(GL_DEPTH_BITS, &v); |
+ params[0] = BoundFramebufferHasDepthAttachment() ? v : 0; |
+ } |
+ return true; |
+ case GL_STENCIL_BITS: |
+ *num_written = 1; |
+ if (params) { |
+ GLint v = 0; |
+ glGetIntegerv(GL_STENCIL_BITS, &v); |
+ params[0] = BoundFramebufferHasStencilAttachment() ? v : 0; |
+ } |
+ return true; |
case GL_COMPRESSED_TEXTURE_FORMATS: |
*num_written = 0; |
// We don't support compressed textures. |
@@ -3400,6 +3543,7 @@ error::Error GLES2DecoderImpl::HandleRegisterSharedIdsCHROMIUM( |
void GLES2DecoderImpl::DoClear(GLbitfield mask) { |
if (CheckFramebufferComplete("glClear")) { |
+ ApplyDirtyState(); |
glClear(mask); |
} |
} |
@@ -3426,6 +3570,7 @@ void GLES2DecoderImpl::DoDrawArrays( |
bool simulated_fixed_attribs = false; |
if (SimulateFixedAttribs(max_vertex_accessed, &simulated_fixed_attribs)) { |
bool textures_set = SetBlackTextureForNonRenderableTextures(); |
+ ApplyDirtyState(); |
glDrawArrays(mode, first, count); |
if (textures_set) { |
RestoreStateForNonRenderableTextures(); |
@@ -3474,6 +3619,9 @@ void GLES2DecoderImpl::DoFramebufferRenderbuffer( |
} |
} |
} |
+ if (framebuffer_info == bound_draw_framebuffer_) { |
+ state_dirty_ = true; |
+ } |
} |
void GLES2DecoderImpl::SetCapabilityState(GLenum cap, bool enabled) { |
@@ -3521,27 +3669,28 @@ void GLES2DecoderImpl::DoColorMask( |
mask_green_ = green; |
mask_blue_ = blue; |
mask_alpha_ = alpha; |
- glColorMask(red, green, blue, alpha); |
+ state_dirty_ = true; |
} |
void GLES2DecoderImpl::DoDepthMask(GLboolean depth) { |
mask_depth_ = depth; |
- glDepthMask(depth); |
+ state_dirty_ = true; |
} |
void GLES2DecoderImpl::DoStencilMask(GLuint mask) { |
mask_stencil_front_ = mask; |
mask_stencil_back_ = mask; |
- glStencilMask(mask); |
+ state_dirty_ = true; |
} |
void GLES2DecoderImpl::DoStencilMaskSeparate(GLenum face, GLuint mask) { |
- if (face == GL_FRONT) { |
+ if (face == GL_FRONT || face == GL_FRONT_AND_BACK) { |
mask_stencil_front_ = mask; |
- } else { |
+ } |
+ if (face == GL_BACK || face == GL_FRONT_AND_BACK) { |
mask_stencil_back_ = mask; |
} |
- glStencilMaskSeparate(face, mask); |
+ state_dirty_ = true; |
} |
// NOTE: There's an assumption here that Texture attachments |
@@ -3586,13 +3735,10 @@ void GLES2DecoderImpl::ClearUnclearedRenderbuffers( |
} |
void GLES2DecoderImpl::RestoreClearState() { |
+ state_dirty_ = true; |
glClearColor(clear_red_, clear_green_, clear_blue_, clear_alpha_); |
- glColorMask(mask_red_, mask_green_, mask_blue_, mask_alpha_); |
glClearStencil(clear_stencil_); |
- glStencilMaskSeparate(GL_FRONT, mask_stencil_front_); |
- glStencilMaskSeparate(GL_BACK, mask_stencil_back_); |
glClearDepth(clear_depth_); |
- glDepthMask(mask_depth_); |
if (enable_scissor_test_) { |
glEnable(GL_SCISSOR_TEST); |
} |
@@ -3638,6 +3784,9 @@ void GLES2DecoderImpl::DoFramebufferTexture2D( |
ClearUnclearedRenderbuffers(target, framebuffer_info); |
} |
} |
+ if (framebuffer_info == bound_draw_framebuffer_) { |
+ state_dirty_ = true; |
+ } |
} |
void GLES2DecoderImpl::DoGetFramebufferAttachmentParameteriv( |
@@ -4433,6 +4582,7 @@ error::Error GLES2DecoderImpl::HandleDrawElements( |
bool simulated_fixed_attribs = false; |
if (SimulateFixedAttribs(max_vertex_accessed, &simulated_fixed_attribs)) { |
bool textures_set = SetBlackTextureForNonRenderableTextures(); |
+ ApplyDirtyState(); |
const GLvoid* indices = reinterpret_cast<const GLvoid*>(offset); |
glDrawElements(mode, count, type, indices); |
if (textures_set) { |
@@ -5648,6 +5798,10 @@ error::Error GLES2DecoderImpl::DoTexImage2D( |
pixels = zero.get(); |
} |
+ if (info->IsAttachedToFramebuffer()) { |
+ state_dirty_ = true; |
+ } |
+ |
if (!teximage2d_faster_than_texsubimage2d_) { |
GLsizei tex_width = 0; |
GLsizei tex_height = 0; |
@@ -5828,6 +5982,10 @@ void GLES2DecoderImpl::DoCopyTexImage2D( |
ScopedResolvedFrameBufferBinder binder(this, false); |
gfx::Size size = GetBoundReadFrameBufferSize(); |
+ if (info->IsAttachedToFramebuffer()) { |
+ state_dirty_ = true; |
+ } |
+ |
// Clip to size to source dimensions |
GLint copyX = 0; |
GLint copyY = 0; |