Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(155)

Unified Diff: gpu/command_buffer/service/gles2_cmd_decoder.cc

Issue 2061743004: Implement native GMB backbuffers in the GLES2 Command Decoder. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Comments from piman. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 74abce022062a0e6a5d22c7e71e7e0d028c44717..e1eea99544f79a8640fd96780d5741671a91c3a0 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -48,6 +48,7 @@
#include "gpu/command_buffer/service/gpu_preferences.h"
#include "gpu/command_buffer/service/gpu_state_tracer.h"
#include "gpu/command_buffer/service/gpu_tracer.h"
+#include "gpu/command_buffer/service/image_factory.h"
#include "gpu/command_buffer/service/image_manager.h"
#include "gpu/command_buffer/service/logger.h"
#include "gpu/command_buffer/service/mailbox_manager.h"
@@ -64,9 +65,11 @@
#include "gpu/command_buffer/service/vertex_array_manager.h"
#include "gpu/command_buffer/service/vertex_attrib_manager.h"
#include "third_party/smhasher/src/City.h"
+#include "ui/gfx/buffer_types.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/gpu_memory_buffer.h"
#include "ui/gfx/overlay_transform.h"
#include "ui/gfx/transform.h"
#include "ui/gl/gl_bindings.h"
@@ -407,6 +410,9 @@ class BackTexture {
// not possible to make it current in order to free the resource.
void Invalidate();
+ // The bind point for the texture.
+ GLenum Target();
+
scoped_refptr<TextureRef> texture_ref() { return texture_ref_; }
GLuint id() const {
@@ -418,6 +424,15 @@ class BackTexture {
}
private:
+ // The texture must be bound to Target() before calling this method.
+ // Returns whether the operation was successful.
+ bool AllocateNativeGpuMemoryBuffer(const gfx::Size& size,
+ GLenum format,
+ bool zero);
+
+ // The texture must be bound to Target() before calling this method.
+ void DestroyNativeGpuMemoryBuffer(bool have_context);
+
MemoryTypeTracker memory_tracker_;
size_t bytes_allocated_;
gfx::Size size_;
@@ -425,16 +440,17 @@ class BackTexture {
scoped_refptr<TextureRef> texture_ref_;
+ // The image that backs the texture, if its backed by a native
+ // GpuMemoryBuffer.
+ scoped_refptr<gl::GLImage> image_;
+
DISALLOW_COPY_AND_ASSIGN(BackTexture);
};
// Encapsulates an OpenGL render buffer of any format.
class BackRenderbuffer {
public:
- explicit BackRenderbuffer(
- RenderbufferManager* renderbuffer_manager,
- MemoryTracker* memory_tracker,
- ContextState* state);
+ explicit BackRenderbuffer(GLES2DecoderImpl* decoder);
~BackRenderbuffer();
// Create a new render buffer.
@@ -459,9 +475,8 @@ class BackRenderbuffer {
}
private:
- RenderbufferManager* renderbuffer_manager_;
+ GLES2DecoderImpl* decoder_;
MemoryTypeTracker memory_tracker_;
- ContextState* state_;
size_t bytes_allocated_;
GLuint id_;
DISALLOW_COPY_AND_ASSIGN(BackRenderbuffer);
@@ -671,7 +686,7 @@ class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient {
// These check the state of the currently bound framebuffer or the
// backbuffer if no framebuffer is bound.
// Check with all attached and enabled color attachments.
- bool BoundFramebufferHasColorAttachmentWithAlpha();
+ bool BoundFramebufferAllowsChangesToAlphaChannel();
bool BoundFramebufferHasDepthAttachment();
bool BoundFramebufferHasStencilAttachment();
@@ -711,6 +726,7 @@ class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient {
friend class ScopedFrameBufferReadPixelHelper;
friend class ScopedResolvedFrameBufferBinder;
friend class BackFramebuffer;
+ friend class BackRenderbuffer;
friend class BackTexture;
enum FramebufferOperation {
@@ -1948,17 +1964,25 @@ class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient {
return error::kNoError;
}
- bool BackBufferHasAlpha() const {
+ // Whether the back buffer exposed to the client has an alpha channel. Note
+ // that this is potentially different from whether the implementation of the
+ // back buffer has an alpha channel.
+ bool ClientExposedBackBufferHasAlpha() const {
if (back_buffer_draw_buffer_ == GL_NONE)
return false;
if (offscreen_target_frame_buffer_.get()) {
- return (offscreen_target_color_format_ == GL_RGBA ||
- offscreen_target_color_format_ == GL_RGBA8);
+ return offscreen_buffer_should_have_alpha_;
}
return (back_buffer_color_format_ == GL_RGBA ||
back_buffer_color_format_ == GL_RGBA8);
}
+ // If the back buffer has a non-emulated alpha channel, the clear color should
+ // be 0. Otherwise, the clear color should be 1.
+ GLfloat BackBufferAlphaClearColor() const {
+ return offscreen_buffer_should_have_alpha_ ? 0.f : 1.f;
+ }
+
// Set remaining commands to process to 0 to force DoCommands to return
// and allow context preemption and GPU watchdog checks in CommandExecutor().
void ExitCommandProcessingEarly() { commands_to_process_ = 0; }
@@ -1988,6 +2012,10 @@ class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient {
GLuint* source_texture_service_id,
GLenum* source_texture_target);
+ // Whether a texture backed by a Chromium Image needs to emulate GL_RGB format
+ // using GL_RGBA and glColorMask.
+ bool ChromiumImageNeedsRGBEmulation();
+
bool InitializeCopyTexImageBlitter(const char* function_name);
bool InitializeCopyTextureCHROMIUM(const char* function_name);
// Generate a member function prototype for each command in an automated and
@@ -2047,7 +2075,12 @@ class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient {
std::unique_ptr<BackRenderbuffer> offscreen_target_color_render_buffer_;
std::unique_ptr<BackRenderbuffer> offscreen_target_depth_render_buffer_;
std::unique_ptr<BackRenderbuffer> offscreen_target_stencil_render_buffer_;
+
+ // The format of the texture or renderbuffer backing the offscreen
+ // framebuffer. Also the format of the texture backing the saved offscreen
+ // framebuffer.
GLenum offscreen_target_color_format_;
+
GLenum offscreen_target_depth_format_;
GLenum offscreen_target_stencil_format_;
GLsizei offscreen_target_samples_;
@@ -2091,6 +2124,9 @@ class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient {
std::unique_ptr<BackTexture> offscreen_resolved_color_texture_;
GLenum offscreen_saved_color_format_;
+ // Whether the client requested an offscreen buffer with an alpha channel.
+ bool offscreen_buffer_should_have_alpha_;
+
std::unique_ptr<QueryManager> query_manager_;
std::unique_ptr<VertexArrayManager> vertex_array_manager_;
@@ -2165,6 +2201,9 @@ class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient {
// An optional behaviour to lose the context and group when OOM.
bool lose_context_when_out_of_memory_;
+ // Forces the backbuffer to use native GMBs rather than a TEXTURE_2D texture.
+ bool should_use_native_gmb_for_backbuffer_;
+
// Log extra info.
bool service_logging_;
@@ -2330,6 +2369,10 @@ ScopedResolvedFrameBufferBinder::ScopedResolvedFrameBufferBinder(
if (!resolve_and_bind_)
return;
+ // TODO(erikchen): On old AMD GPUs on macOS, glColorMask doesn't work
+ // correctly for multisampled renderbuffers and the alpha channel can be
+ // overwritten. Add a workaround to clear the alpha channel before resolving.
+ // https://crbug.com/602484.
ScopedGLErrorSuppressor suppressor(
"ScopedResolvedFrameBufferBinder::ctor", decoder_->GetErrorState());
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT,
@@ -2428,13 +2471,17 @@ ScopedFrameBufferReadPixelHelper::~ScopedFrameBufferReadPixelHelper() {
BackTexture::BackTexture(GLES2DecoderImpl* decoder)
: memory_tracker_(decoder->memory_tracker()),
bytes_allocated_(0),
- decoder_(decoder) {}
+ decoder_(decoder) {
+ DCHECK(!decoder_->should_use_native_gmb_for_backbuffer_ ||
+ decoder_->GetContextGroup()->image_factory());
+}
BackTexture::~BackTexture() {
// This does not destroy the render texture because that would require that
// the associated GL context was current. Just check that it was explicitly
// destroyed.
DCHECK_EQ(id(), 0u);
+ DCHECK(!image_.get());
}
void BackTexture::Create() {
@@ -2444,7 +2491,7 @@ void BackTexture::Create() {
GLuint id;
glGenTextures(1, &id);
- GLenum target = GL_TEXTURE_2D;
+ GLenum target = Target();
ScopedTextureBinder binder(&decoder_->state_, id, target);
// No client id is necessary because this texture will never be directly
@@ -2482,7 +2529,7 @@ bool BackTexture::AllocateStorage(
DCHECK_NE(id(), 0u);
ScopedGLErrorSuppressor suppressor("BackTexture::AllocateStorage",
decoder_->state_.GetErrorState());
- ScopedTextureBinder binder(&decoder_->state_, id(), GL_TEXTURE_2D);
+ ScopedTextureBinder binder(&decoder_->state_, id(), Target());
uint32_t image_size = 0;
GLES2Util::ComputeImageDataSizes(
size.width(), size.height(), 1, format, GL_UNSIGNED_BYTE, 8, &image_size,
@@ -2492,31 +2539,33 @@ bool BackTexture::AllocateStorage(
return false;
}
- std::unique_ptr<char[]> zero_data;
- if (zero) {
- zero_data.reset(new char[image_size]);
- memset(zero_data.get(), 0, image_size);
- }
-
- glTexImage2D(GL_TEXTURE_2D,
- 0, // mip level
- format,
- size.width(),
- size.height(),
- 0, // border
- format,
- GL_UNSIGNED_BYTE,
- zero_data.get());
-
+ bool success = false;
size_ = size;
- decoder_->texture_manager()->SetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D,
- 0, // level
- GL_RGBA, size_.width(), size_.height(),
- 1, // depth
- 0, // border
- GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(size_));
+ if (decoder_->should_use_native_gmb_for_backbuffer_) {
+ DestroyNativeGpuMemoryBuffer(true);
+ success = AllocateNativeGpuMemoryBuffer(size, format, zero);
+ } else {
+ std::unique_ptr<char[]> zero_data;
+ if (zero) {
+ zero_data.reset(new char[image_size]);
+ memset(zero_data.get(), 0, image_size);
+ }
+
+ glTexImage2D(Target(),
+ 0, // mip level
+ format, size.width(), size.height(),
+ 0, // border
+ format, GL_UNSIGNED_BYTE, zero_data.get());
+ decoder_->texture_manager()->SetLevelInfo(
+ texture_ref_.get(), Target(),
+ 0, // level
+ GL_RGBA, size.width(), size.height(),
+ 1, // depth
+ 0, // border
+ GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect(size));
+ success = glGetError() == GL_NO_ERROR;
+ }
- bool success = glGetError() == GL_NO_ERROR;
if (success) {
memory_tracker_.TrackMemFree(bytes_allocated_);
bytes_allocated_ = image_size;
@@ -2529,17 +2578,20 @@ void BackTexture::Copy(const gfx::Size& size, GLenum format) {
DCHECK_NE(id(), 0u);
ScopedGLErrorSuppressor suppressor("BackTexture::Copy",
decoder_->state_.GetErrorState());
- ScopedTextureBinder binder(&decoder_->state_, id(), GL_TEXTURE_2D);
- glCopyTexImage2D(GL_TEXTURE_2D,
+ ScopedTextureBinder binder(&decoder_->state_, id(), Target());
+ glCopyTexImage2D(Target(),
0, // level
- format,
- 0, 0,
- size.width(),
- size.height(),
+ format, 0, 0, size.width(), size.height(),
0); // border
}
void BackTexture::Destroy() {
+ if (image_) {
+ DCHECK(texture_ref_);
+ ScopedTextureBinder binder(&decoder_->state_, id(), Target());
+ DestroyNativeGpuMemoryBuffer(true);
+ }
+
if (texture_ref_) {
ScopedGLErrorSuppressor suppressor("BackTexture::Destroy",
decoder_->state_.GetErrorState());
@@ -2550,23 +2602,86 @@ void BackTexture::Destroy() {
}
void BackTexture::Invalidate() {
+ if (image_) {
+ DestroyNativeGpuMemoryBuffer(false);
+ image_ = nullptr;
+ }
if (texture_ref_) {
texture_ref_->ForceContextLost();
texture_ref_ = nullptr;
}
}
-BackRenderbuffer::BackRenderbuffer(
- RenderbufferManager* renderbuffer_manager,
- MemoryTracker* memory_tracker,
- ContextState* state)
- : renderbuffer_manager_(renderbuffer_manager),
- memory_tracker_(memory_tracker),
- state_(state),
- bytes_allocated_(0),
- id_(0) {
+GLenum BackTexture::Target() {
+ return decoder_->should_use_native_gmb_for_backbuffer_
+ ? decoder_->GetContextGroup()
+ ->image_factory()
+ ->RequiredTextureType()
+ : GL_TEXTURE_2D;
+}
+
+bool BackTexture::AllocateNativeGpuMemoryBuffer(const gfx::Size& size,
+ GLenum format,
+ bool zero) {
+ gfx::BufferFormat buffer_format = gfx::BufferFormat::RGBA_8888;
+ scoped_refptr<gl::GLImage> image =
+ decoder_->GetContextGroup()->image_factory()->CreateAnonymousImage(
+ size, buffer_format, format);
+ if (!image || !image->BindTexImage(Target()))
+ return false;
+
+ image_ = image;
+ decoder_->texture_manager()->SetLevelInfo(
+ texture_ref_.get(), Target(), 0, image_->GetInternalFormat(),
+ size.width(), size.height(), 1, 0, image_->GetInternalFormat(),
+ GL_UNSIGNED_BYTE, gfx::Rect(size));
+ decoder_->texture_manager()->SetLevelImage(texture_ref_.get(), Target(), 0,
+ image_.get(), Texture::BOUND);
+
+ // Ignore the zero flag if the alpha channel needs to be cleared for RGB
+ // emulation.
+ bool needs_clear_for_rgb_emulation =
+ !decoder_->offscreen_buffer_should_have_alpha_ &&
+ decoder_->ChromiumImageNeedsRGBEmulation();
+ if (zero || needs_clear_for_rgb_emulation) {
+ GLuint fbo;
+ glGenFramebuffersEXT(1, &fbo);
+ {
+ ScopedFrameBufferBinder binder(decoder_, fbo);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, Target(),
+ id(), 0);
+ glClearColor(0, 0, 0, decoder_->BackBufferAlphaClearColor());
+ decoder_->state_.SetDeviceColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ decoder_->state_.SetDeviceCapabilityState(GL_SCISSOR_TEST, false);
+ glClear(GL_COLOR_BUFFER_BIT);
+ decoder_->RestoreClearState();
+ }
+ glDeleteFramebuffersEXT(1, &fbo);
+ }
+ return true;
+}
+
+void BackTexture::DestroyNativeGpuMemoryBuffer(bool have_context) {
+ if (image_) {
+ ScopedGLErrorSuppressor suppressor(
+ "BackTexture::DestroyNativeGpuMemoryBuffer",
+ decoder_->state_.GetErrorState());
+
+ image_->ReleaseTexImage(Target());
+ image_->Destroy(have_context);
+
+ decoder_->texture_manager()->SetLevelImage(texture_ref_.get(), Target(), 0,
+ nullptr, Texture::UNBOUND);
+ image_ = nullptr;
+ }
}
+BackRenderbuffer::BackRenderbuffer(GLES2DecoderImpl* decoder)
+ : decoder_(decoder),
+ memory_tracker_(decoder->memory_tracker()),
+ bytes_allocated_(0),
+ id_(0) {}
+
BackRenderbuffer::~BackRenderbuffer() {
// This does not destroy the render buffer because that would require that
// the associated GL context was current. Just check that it was explicitly
@@ -2576,7 +2691,7 @@ BackRenderbuffer::~BackRenderbuffer() {
void BackRenderbuffer::Create() {
ScopedGLErrorSuppressor suppressor("BackRenderbuffer::Create",
- state_->GetErrorState());
+ decoder_->state_.GetErrorState());
Destroy();
glGenRenderbuffersEXT(1, &id_);
}
@@ -2585,13 +2700,13 @@ bool BackRenderbuffer::AllocateStorage(const FeatureInfo* feature_info,
const gfx::Size& size,
GLenum format,
GLsizei samples) {
- ScopedGLErrorSuppressor suppressor(
- "BackRenderbuffer::AllocateStorage", state_->GetErrorState());
- ScopedRenderBufferBinder binder(state_, id_);
+ ScopedGLErrorSuppressor suppressor("BackRenderbuffer::AllocateStorage",
+ decoder_->state_.GetErrorState());
+ ScopedRenderBufferBinder binder(&decoder_->state_, id_);
uint32_t estimated_size = 0;
- if (!renderbuffer_manager_->ComputeEstimatedRenderbufferSize(
- size.width(), size.height(), samples, format, &estimated_size)) {
+ if (!decoder_->renderbuffer_manager()->ComputeEstimatedRenderbufferSize(
+ size.width(), size.height(), samples, format, &estimated_size)) {
return false;
}
@@ -2612,6 +2727,26 @@ bool BackRenderbuffer::AllocateStorage(const FeatureInfo* feature_info,
size.width(),
size.height());
}
+
+ bool alpha_channel_needs_clear =
+ (format == GL_RGBA || format == GL_RGBA8) &&
+ !decoder_->offscreen_buffer_should_have_alpha_;
+ if (alpha_channel_needs_clear) {
+ GLuint fbo;
+ glGenFramebuffersEXT(1, &fbo);
+ {
+ ScopedFrameBufferBinder binder(decoder_, fbo);
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_RENDERBUFFER, id_);
+ glClearColor(0, 0, 0, decoder_->BackBufferAlphaClearColor());
+ decoder_->state_.SetDeviceColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ decoder_->state_.SetDeviceCapabilityState(GL_SCISSOR_TEST, false);
+ glClear(GL_COLOR_BUFFER_BIT);
+ decoder_->RestoreClearState();
+ }
+ glDeleteFramebuffersEXT(1, &fbo);
+ }
+
bool success = glGetError() == GL_NO_ERROR;
if (success) {
// Mark the previously allocated bytes as free.
@@ -2626,7 +2761,7 @@ bool BackRenderbuffer::AllocateStorage(const FeatureInfo* feature_info,
void BackRenderbuffer::Destroy() {
if (id_ != 0) {
ScopedGLErrorSuppressor suppressor("BackRenderbuffer::Destroy",
- state_->GetErrorState());
+ decoder_->state_.GetErrorState());
glDeleteRenderbuffersEXT(1, &id_);
id_ = 0;
}
@@ -2663,11 +2798,8 @@ void BackFramebuffer::AttachRenderTexture(BackTexture* texture) {
"BackFramebuffer::AttachRenderTexture", decoder_->GetErrorState());
ScopedFrameBufferBinder binder(decoder_, id_);
GLuint attach_id = texture ? texture->id() : 0;
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER,
- GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D,
- attach_id,
- 0);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ texture->Target(), attach_id, 0);
}
void BackFramebuffer::AttachRenderBuffer(GLenum target,
@@ -2727,6 +2859,7 @@ GLES2DecoderImpl::GLES2DecoderImpl(ContextGroup* group)
offscreen_target_samples_(0),
offscreen_target_buffer_preserved_(true),
offscreen_saved_color_format_(0),
+ offscreen_buffer_should_have_alpha_(false),
back_buffer_color_format_(0),
back_buffer_has_depth_(false),
back_buffer_has_stencil_(false),
@@ -2753,6 +2886,7 @@ GLES2DecoderImpl::GLES2DecoderImpl(ContextGroup* group)
shader_texture_lod_explicitly_enabled_(false),
compile_shader_always_succeeds_(false),
lose_context_when_out_of_memory_(false),
+ should_use_native_gmb_for_backbuffer_(false),
service_logging_(
group_->gpu_preferences().enable_gpu_service_logging_gpu),
viewport_max_width_(0),
@@ -2818,6 +2952,31 @@ bool GLES2DecoderImpl::Initialize(
lose_context_when_out_of_memory_ =
attrib_helper.lose_context_when_out_of_memory;
+ should_use_native_gmb_for_backbuffer_ =
+ attrib_helper.should_use_native_gmb_for_backbuffer;
+ if (should_use_native_gmb_for_backbuffer_) {
+ gpu::ImageFactory* image_factory = group_->image_factory();
+ bool supported = false;
+ if (image_factory) {
+ switch (image_factory->RequiredTextureType()) {
+ case GL_TEXTURE_RECTANGLE_ARB:
+ supported = feature_info_->feature_flags().arb_texture_rectangle;
+ break;
+ case GL_TEXTURE_2D:
+ supported = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (!supported) {
+ group_ = NULL; // Must not destroy ContextGroup if it is not initialized.
+ Destroy(true);
+ return false;
+ }
+ }
+
// If the failIfMajorPerformanceCaveat context creation attribute was true
// and we are using a software renderer, fail.
if (attrib_helper.fail_if_major_perf_caveat &&
@@ -2936,6 +3095,15 @@ bool GLES2DecoderImpl::Initialize(
GLint alpha_bits = 0;
if (offscreen) {
+ offscreen_buffer_should_have_alpha_ = attrib_helper.alpha_size > 0;
+
+ // Whether the offscreen buffer texture should have an alpha channel. Does
+ // not include logic from workarounds.
+ bool offscreen_buffer_texture_needs_alpha =
+ offscreen_buffer_should_have_alpha_ ||
+ (ChromiumImageNeedsRGBEmulation() &&
+ attrib_helper.should_use_native_gmb_for_backbuffer);
+
if (attrib_helper.samples > 0 && attrib_helper.sample_buffers > 0 &&
features().chromium_framebuffer_multisample) {
// Per ext_framebuffer_multisample spec, need max bound on sample count.
@@ -2957,12 +3125,13 @@ bool GLES2DecoderImpl::Initialize(
// little precision. Don't enable multisampling unless 8-bit render
// buffer formats are available--instead fall back to 8-bit textures.
if (rgb8_supported && offscreen_target_samples_ > 1) {
- offscreen_target_color_format_ = attrib_helper.alpha_size > 0 ?
- GL_RGBA8 : GL_RGB8;
+ offscreen_target_color_format_ =
+ offscreen_buffer_texture_needs_alpha ? GL_RGBA8 : GL_RGB8;
} else {
offscreen_target_samples_ = 1;
offscreen_target_color_format_ =
- attrib_helper.alpha_size > 0 || workarounds().disable_gl_rgb_format
+ offscreen_buffer_texture_needs_alpha ||
+ workarounds().disable_gl_rgb_format
? GL_RGBA
: GL_RGB;
}
@@ -2987,7 +3156,8 @@ bool GLES2DecoderImpl::Initialize(
}
} else {
offscreen_target_color_format_ =
- attrib_helper.alpha_size > 0 || workarounds().disable_gl_rgb_format
+ offscreen_buffer_texture_needs_alpha ||
+ workarounds().disable_gl_rgb_format
? GL_RGBA
: GL_RGB;
@@ -3011,10 +3181,10 @@ bool GLES2DecoderImpl::Initialize(
}
}
- offscreen_saved_color_format_ =
- attrib_helper.alpha_size > 0 || workarounds().disable_gl_rgb_format
- ? GL_RGBA
- : GL_RGB;
+ offscreen_saved_color_format_ = offscreen_buffer_texture_needs_alpha ||
+ workarounds().disable_gl_rgb_format
+ ? GL_RGBA
+ : GL_RGB;
// Create the target frame buffer. This is the one that the client renders
// directly to.
@@ -3025,18 +3195,15 @@ bool GLES2DecoderImpl::Initialize(
// attached to the offscreen frame buffer. The render buffer has more
// limited formats available to it, but the texture can't do multisampling.
if (IsOffscreenBufferMultisampled()) {
- offscreen_target_color_render_buffer_.reset(new BackRenderbuffer(
- renderbuffer_manager(), memory_tracker(), &state_));
+ offscreen_target_color_render_buffer_.reset(new BackRenderbuffer(this));
offscreen_target_color_render_buffer_->Create();
} else {
offscreen_target_color_texture_.reset(new BackTexture(this));
offscreen_target_color_texture_->Create();
}
- offscreen_target_depth_render_buffer_.reset(new BackRenderbuffer(
- renderbuffer_manager(), memory_tracker(), &state_));
+ offscreen_target_depth_render_buffer_.reset(new BackRenderbuffer(this));
offscreen_target_depth_render_buffer_->Create();
- offscreen_target_stencil_render_buffer_.reset(new BackRenderbuffer(
- renderbuffer_manager(), memory_tracker(), &state_));
+ offscreen_target_stencil_render_buffer_.reset(new BackRenderbuffer(this));
offscreen_target_stencil_render_buffer_->Create();
// Create the saved offscreen texture. The target frame buffer is copied
@@ -3349,10 +3516,10 @@ Capabilities GLES2DecoderImpl::GetCapabilities() {
feature_info_->feature_flags().ext_discard_framebuffer;
caps.sync_query = feature_info_->feature_flags().chromium_sync_query;
+ caps.chromium_image_rgb_emulation = ChromiumImageNeedsRGBEmulation();
#if defined(OS_MACOSX)
// This is unconditionally true on mac, no need to test for it at runtime.
caps.iosurface = true;
- caps.chromium_image_rgb_emulation = true;
#endif
caps.post_sub_buffer = supports_post_sub_buffer_;
@@ -3915,7 +4082,7 @@ bool GLES2DecoderImpl::CheckFramebufferValid(
if (surfaceless_)
return false;
if (backbuffer_needs_clear_bits_ && clear_uncleared_images) {
- glClearColor(0, 0, 0, BackBufferHasAlpha() ? 0 : 1.f);
+ glClearColor(0, 0, 0, BackBufferAlphaClearColor());
state_.SetDeviceColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glClearStencil(0);
state_.SetDeviceStencilMaskSeparate(GL_FRONT, kDefaultStencilMask);
@@ -4582,10 +4749,8 @@ bool GLES2DecoderImpl::ResizeOffscreenFrameBuffer(const gfx::Size& size) {
DCHECK(offscreen_target_color_format_);
if (IsOffscreenBufferMultisampled()) {
if (!offscreen_target_color_render_buffer_->AllocateStorage(
- feature_info_.get(),
- offscreen_size_,
- offscreen_target_color_format_,
- offscreen_target_samples_)) {
+ feature_info_.get(), offscreen_size_,
+ offscreen_target_color_format_, offscreen_target_samples_)) {
LOG(ERROR) << "GLES2DecoderImpl::ResizeOffscreenFrameBuffer failed "
<< "to allocate storage for offscreen target color buffer.";
return false;
@@ -4655,7 +4820,7 @@ bool GLES2DecoderImpl::ResizeOffscreenFrameBuffer(const gfx::Size& size) {
// Clear the target frame buffer.
{
ScopedFrameBufferBinder binder(this, offscreen_target_frame_buffer_->id());
- glClearColor(0, 0, 0, BackBufferHasAlpha() ? 0 : 1.f);
+ glClearColor(0, 0, 0, BackBufferAlphaClearColor());
state_.SetDeviceColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glClearStencil(0);
state_.SetDeviceStencilMaskSeparate(GL_FRONT, kDefaultStencilMask);
@@ -5038,12 +5203,20 @@ void GLES2DecoderImpl::DoBindBufferRange(GLenum target, GLuint index,
kBindBufferRange, "glBindBufferRange");
}
-bool GLES2DecoderImpl::BoundFramebufferHasColorAttachmentWithAlpha() {
+bool GLES2DecoderImpl::BoundFramebufferAllowsChangesToAlphaChannel() {
Framebuffer* framebuffer =
GetFramebufferInfoForTarget(GL_DRAW_FRAMEBUFFER_EXT);
if (framebuffer)
return framebuffer->HasAlphaMRT();
- return BackBufferHasAlpha();
+ if (back_buffer_draw_buffer_ == GL_NONE)
+ return false;
+ if (offscreen_target_frame_buffer_.get()) {
+ GLenum format = offscreen_target_color_format_;
+ return (format == GL_RGBA || format == GL_RGBA8) &&
+ offscreen_buffer_should_have_alpha_;
+ }
+ return (back_buffer_color_format_ == GL_RGBA ||
+ back_buffer_color_format_ == GL_RGBA8);
}
bool GLES2DecoderImpl::BoundFramebufferHasDepthAttachment() {
@@ -5073,11 +5246,10 @@ bool GLES2DecoderImpl::BoundFramebufferHasStencilAttachment() {
void GLES2DecoderImpl::ApplyDirtyState() {
if (framebuffer_state_.clear_state_dirty) {
- bool have_alpha = BoundFramebufferHasColorAttachmentWithAlpha();
- state_.SetDeviceColorMask(state_.color_mask_red,
- state_.color_mask_green,
+ bool allows_alpha_change = BoundFramebufferAllowsChangesToAlphaChannel();
+ state_.SetDeviceColorMask(state_.color_mask_red, state_.color_mask_green,
state_.color_mask_blue,
- state_.color_mask_alpha && have_alpha);
+ state_.color_mask_alpha && allows_alpha_change);
bool have_depth = BoundFramebufferHasDepthAttachment();
state_.SetDeviceDepthMask(state_.depth_mask && have_depth);
@@ -5868,7 +6040,7 @@ bool GLES2DecoderImpl::GetHelper(
}
}
} else {
- v = (BackBufferHasAlpha() ? 8 : 0);
+ v = (ClientExposedBackBufferHasAlpha() ? 8 : 0);
}
params[0] = v;
}
@@ -13229,7 +13401,7 @@ void GLES2DecoderImpl::DoSwapBuffers() {
{
ScopedFrameBufferBinder binder(this,
offscreen_saved_frame_buffer_->id());
- glClearColor(0, 0, 0, 0);
+ glClearColor(0, 0, 0, BackBufferAlphaClearColor());
state_.SetDeviceColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
state_.SetDeviceCapabilityState(GL_SCISSOR_TEST, false);
glClear(GL_COLOR_BUFFER_BIT);
@@ -16714,6 +16886,11 @@ bool GLES2DecoderImpl::NeedsCopyTextureImageWorkaround(
return true;
}
+bool GLES2DecoderImpl::ChromiumImageNeedsRGBEmulation() {
+ gpu::ImageFactory* factory = GetContextGroup()->image_factory();
+ return factory ? !factory->SupportsFormatRGB() : false;
+}
+
error::Error GLES2DecoderImpl::HandleBindFragmentInputLocationCHROMIUMBucket(
uint32_t immediate_data_size,
const void* cmd_data) {
« no previous file with comments | « gpu/command_buffer/service/feature_info.h ('k') | gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698