summaryrefslogtreecommitdiffstats
path: root/gpu
diff options
context:
space:
mode:
authorenne@chromium.org <enne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-01 20:06:02 +0000
committerenne@chromium.org <enne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-01 20:06:02 +0000
commit34ff8b0ce22406a4f8777ea3da9e08fc02af6beb (patch)
treec59971cc688bbb3aeb383e3a36cb29164bbde589 /gpu
parent1599077a645a03c31c09efe57befaefbe00c958a (diff)
downloadchromium_src-34ff8b0ce22406a4f8777ea3da9e08fc02af6beb.zip
chromium_src-34ff8b0ce22406a4f8777ea3da9e08fc02af6beb.tar.gz
chromium_src-34ff8b0ce22406a4f8777ea3da9e08fc02af6beb.tar.bz2
Add offscreen context creation attributes to GGL.
View contexts and more extensive color format picking not handled yet. BUG=39849 TEST=WebGL conformance tests (context*.html) Review URL: http://codereview.chromium.org/3302019 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@61220 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu')
-rw-r--r--gpu/command_buffer/client/gles2_demo.cc3
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc486
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.h3
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_mock.h5
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc4
-rw-r--r--gpu/command_buffer/service/gpu_processor.cc2
-rw-r--r--gpu/command_buffer/service/gpu_processor.h4
-rw-r--r--gpu/command_buffer/service/gpu_processor_linux.cc2
-rw-r--r--gpu/command_buffer/service/gpu_processor_mac.cc3
-rw-r--r--gpu/command_buffer/service/gpu_processor_win.cc2
-rw-r--r--gpu/demos/framework/window.cc4
11 files changed, 398 insertions, 120 deletions
diff --git a/gpu/command_buffer/client/gles2_demo.cc b/gpu/command_buffer/client/gles2_demo.cc
index 1cfeaca..9224866 100644
--- a/gpu/command_buffer/client/gles2_demo.cc
+++ b/gpu/command_buffer/client/gles2_demo.cc
@@ -59,6 +59,7 @@ bool GLES2Demo::Setup(void* hwnd, int32 size) {
GPUProcessor* gpu_processor = new GPUProcessor(command_buffer.get());
if (!gpu_processor->Initialize(reinterpret_cast<HWND>(hwnd),
gfx::Size(),
+ std::vector<int32>(),
NULL,
0)) {
return NULL;
@@ -225,5 +226,3 @@ int main(int argc, char** argv) {
return EXIT_SUCCESS;
}
-
-
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index df03682..a09c6ce 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -114,6 +114,14 @@ const CommandInfo g_command_info[] = {
#undef GLES2_CMD_OP
};
+static bool IsAngle() {
+#if defined(OS_WIN)
+ return gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2;
+#else
+ return false;
+#endif
+}
+
// This class prevents any GL errors that occur when it is in scope from
// being reported to the client.
class ScopedGLErrorSuppressor {
@@ -162,6 +170,20 @@ class ScopedFrameBufferBinder {
DISALLOW_COPY_AND_ASSIGN(ScopedFrameBufferBinder);
};
+// Temporarily changes a decoder's bound frame buffer to a resolved version of
+// the multisampled offscreen render buffer if and only if that buffer is
+// currently bound and is multisampled.
+class ScopedResolvedFrameBufferBinder {
+ public:
+ explicit ScopedResolvedFrameBufferBinder(GLES2DecoderImpl* decoder);
+ ~ScopedResolvedFrameBufferBinder();
+
+ private:
+ GLES2DecoderImpl* decoder_;
+ bool resolve_and_bind_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedResolvedFrameBufferBinder);
+};
+
// Temporarily switch to a decoder's default GL context, having known default
// state.
class ScopedDefaultGLContext {
@@ -184,7 +206,7 @@ class Texture {
void Create();
// Set the initial size and format of a render texture or resize it.
- bool AllocateStorage(const gfx::Size& size);
+ bool AllocateStorage(const gfx::Size& size, GLenum format);
// Copy the contents of the currently bound frame buffer.
void Copy(const gfx::Size& size);
@@ -218,7 +240,7 @@ class RenderBuffer {
void Create();
// Set the initial size and format of a render buffer or resize it.
- bool AllocateStorage(const gfx::Size& size, GLenum format);
+ bool AllocateStorage(const gfx::Size& size, GLenum format, GLsizei samples);
// Destroy the render buffer. This must be explicitly called before destroying
// this object.
@@ -269,6 +291,95 @@ class FrameBuffer {
GLuint id_;
DISALLOW_COPY_AND_ASSIGN(FrameBuffer);
};
+
+class ContextCreationAttribParser {
+ public:
+ ContextCreationAttribParser();
+ bool Parse(const std::vector<int32>& attribs);
+
+ // -1 if invalid or unspecified.
+ int32 alpha_size_;
+ int32 blue_size_;
+ int32 green_size_;
+ int32 red_size_;
+ int32 depth_size_;
+ int32 stencil_size_;
+ int32 samples_;
+ int32 sample_buffers_;
+};
+
+ContextCreationAttribParser::ContextCreationAttribParser()
+ : alpha_size_(-1),
+ blue_size_(-1),
+ green_size_(-1),
+ red_size_(-1),
+ depth_size_(-1),
+ stencil_size_(-1),
+ samples_(-1),
+ sample_buffers_(-1) {
+}
+
+bool ContextCreationAttribParser::Parse(const std::vector<int32>& attribs) {
+ // From <EGL/egl.h>.
+ const int32 EGL_ALPHA_SIZE = 0x3021;
+ const int32 EGL_BLUE_SIZE = 0x3022;
+ const int32 EGL_GREEN_SIZE = 0x3023;
+ const int32 EGL_RED_SIZE = 0x3024;
+ const int32 EGL_DEPTH_SIZE = 0x3025;
+ const int32 EGL_STENCIL_SIZE = 0x3026;
+ const int32 EGL_SAMPLES = 0x3031;
+ const int32 EGL_SAMPLE_BUFFERS = 0x3032;
+ const int32 EGL_NONE = 0x3038;
+
+ for (size_t i = 0; i < attribs.size(); i += 2) {
+ const int32 attrib = attribs[i];
+ if (i + 1 >= attribs.size()) {
+ if (attrib == EGL_NONE)
+ return true;
+
+ DLOG(ERROR) << "Missing value after context creation attribute: "
+ << attrib;
+ return false;
+ }
+
+ const int32 value = attribs[i+1];
+ switch (attrib) {
+ case EGL_ALPHA_SIZE:
+ alpha_size_ = value;
+ break;
+ case EGL_BLUE_SIZE:
+ blue_size_ = value;
+ break;
+ case EGL_GREEN_SIZE:
+ green_size_ = value;
+ break;
+ case EGL_RED_SIZE:
+ red_size_ = value;
+ break;
+ case EGL_DEPTH_SIZE:
+ depth_size_ = value;
+ break;
+ case EGL_STENCIL_SIZE:
+ stencil_size_ = value;
+ break;
+ case EGL_SAMPLES:
+ samples_ = value;
+ break;
+ case EGL_SAMPLE_BUFFERS:
+ sample_buffers_ = value;
+ break;
+ case EGL_NONE:
+ // Terminate list, even if more attributes.
+ return true;
+ default:
+ DLOG(ERROR) << "Invalid context creation attribute: " << attrib;
+ return false;
+ }
+ }
+
+ return true;
+}
+
// } // anonymous namespace.
GLES2Decoder::GLES2Decoder(ContextGroup* group)
@@ -528,6 +639,7 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
// Overridden from GLES2Decoder.
virtual bool Initialize(gfx::GLContext* context,
const gfx::Size& size,
+ const std::vector<int32>& attribs,
GLES2Decoder* parent,
uint32 parent_client_texture_id);
virtual void Destroy();
@@ -549,6 +661,7 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
private:
friend class ScopedGLErrorSuppressor;
friend class ScopedDefaultGLContext;
+ friend class ScopedResolvedFrameBufferBinder;
friend class RenderBuffer;
friend class FrameBuffer;
@@ -602,6 +715,10 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
return group_->texture_manager();
}
+ bool IsOffscreenBufferMultisampled() const {
+ return offscreen_target_samples_ > 1;
+ }
+
// Creates a TextureInfo for the given texture.
TextureManager::TextureInfo* CreateTextureInfo(
GLuint client_id, GLuint service_id) {
@@ -1171,6 +1288,9 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
// the next call to SwapBuffers.
gfx::Size pending_offscreen_size_;
+ // Current width and height of the offscreen frame buffer.
+ gfx::Size offscreen_size_;
+
// Current GL error bits.
uint32 error_bits_;
@@ -1238,20 +1358,25 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
// The currently bound renderbuffer
RenderbufferManager::RenderbufferInfo::Ref bound_renderbuffer_;
- bool anti_aliased_;
-
// 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_.
// offscreen_target_stencil_render_buffer_ is unused.
scoped_ptr<FrameBuffer> offscreen_target_frame_buffer_;
scoped_ptr<Texture> offscreen_target_color_texture_;
+ scoped_ptr<RenderBuffer> offscreen_target_color_render_buffer_;
scoped_ptr<RenderBuffer> offscreen_target_depth_render_buffer_;
scoped_ptr<RenderBuffer> offscreen_target_stencil_render_buffer_;
+ GLenum offscreen_target_color_format_;
+ GLenum offscreen_target_depth_format_;
+ GLenum offscreen_target_stencil_format_;
+ GLsizei offscreen_target_samples_;
GLuint copy_texture_to_parent_texture_fb_;
- // The copy that is saved when SwapBuffers is called.
+ // The copy that is saved when SwapBuffers is called. It is also
+ // used as the destination for multi-sample resolves.
+ scoped_ptr<FrameBuffer> offscreen_saved_frame_buffer_;
scoped_ptr<Texture> offscreen_saved_color_texture_;
scoped_ptr<Callback0::Type> swap_buffers_callback_;
@@ -1270,9 +1395,6 @@ class GLES2DecoderImpl : public base::SupportsWeakPtr<GLES2DecoderImpl>,
const Validators* validators_;
FeatureInfo* feature_info_;
- // Supported extensions.
- bool depth24_stencil8_oes_supported_;
-
DISALLOW_COPY_AND_ASSIGN(GLES2DecoderImpl);
};
@@ -1325,6 +1447,40 @@ ScopedFrameBufferBinder::~ScopedFrameBufferBinder() {
decoder_->RestoreCurrentFramebufferBindings();
}
+ScopedResolvedFrameBufferBinder::ScopedResolvedFrameBufferBinder(
+ GLES2DecoderImpl* decoder) : decoder_(decoder) {
+ resolve_and_bind_ = (decoder_->offscreen_target_frame_buffer_.get() &&
+ decoder_->IsOffscreenBufferMultisampled() &&
+ !decoder_->bound_read_framebuffer_.get());
+ if (!resolve_and_bind_)
+ return;
+
+ ScopedGLErrorSuppressor suppressor(decoder_);
+ glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT,
+ decoder_->offscreen_target_frame_buffer_->id());
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT,
+ decoder_->offscreen_saved_frame_buffer_->id());
+ const int width = decoder_->offscreen_size_.width();
+ const int height = decoder_->offscreen_size_.height();
+ if (IsAngle()) {
+ glBlitFramebufferANGLE(0, 0, width, height, 0, 0, width, height,
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ } else {
+ glBlitFramebufferEXT(0, 0, width, height, 0, 0, width, height,
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ }
+ glBindFramebufferEXT(GL_FRAMEBUFFER,
+ decoder_->offscreen_saved_frame_buffer_->id());
+}
+
+ScopedResolvedFrameBufferBinder::~ScopedResolvedFrameBufferBinder() {
+ if (!resolve_and_bind_)
+ return;
+
+ ScopedGLErrorSuppressor suppressor(decoder_);
+ decoder_->RestoreCurrentFramebufferBindings();
+}
+
Texture::Texture(GLES2DecoderImpl* decoder)
: decoder_(decoder),
id_(0) {
@@ -1343,7 +1499,7 @@ void Texture::Create() {
glGenTextures(1, &id_);
}
-bool Texture::AllocateStorage(const gfx::Size& size) {
+bool Texture::AllocateStorage(const gfx::Size& size, GLenum format) {
DCHECK_NE(id_, 0u);
ScopedGLErrorSuppressor suppressor(decoder_);
ScopedTexture2DBinder binder(decoder_, id_);
@@ -1355,11 +1511,11 @@ bool Texture::AllocateStorage(const gfx::Size& size) {
glTexImage2D(GL_TEXTURE_2D,
0, // mip level
- GL_RGBA,
+ format,
size.width(),
size.height(),
0, // border
- GL_RGBA,
+ format,
GL_UNSIGNED_BYTE,
NULL);
@@ -1407,13 +1563,30 @@ void RenderBuffer::Create() {
glGenRenderbuffersEXT(1, &id_);
}
-bool RenderBuffer::AllocateStorage(const gfx::Size& size, GLenum format) {
+bool RenderBuffer::AllocateStorage(const gfx::Size& size, GLenum format,
+ GLsizei samples) {
ScopedGLErrorSuppressor suppressor(decoder_);
ScopedRenderBufferBinder binder(decoder_, id_);
- glRenderbufferStorageEXT(GL_RENDERBUFFER,
- format,
- size.width(),
- size.height());
+ if (samples <= 1) {
+ glRenderbufferStorageEXT(GL_RENDERBUFFER,
+ format,
+ size.width(),
+ size.height());
+ } else {
+ if (IsAngle()) {
+ glRenderbufferStorageMultisampleANGLE(GL_RENDERBUFFER,
+ samples,
+ format,
+ size.width(),
+ size.height());
+ } else {
+ glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER,
+ samples,
+ format,
+ size.width(),
+ size.height());
+ }
+ }
return glGetError() == GL_NO_ERROR;
}
@@ -1515,12 +1688,14 @@ GLES2DecoderImpl::GLES2DecoderImpl(ContextGroup* group)
clear_depth_(1.0f),
mask_depth_(true),
enable_scissor_test_(false),
- anti_aliased_(false),
+ offscreen_target_color_format_(0),
+ offscreen_target_depth_format_(0),
+ offscreen_target_stencil_format_(0),
+ offscreen_target_samples_(0),
current_decoder_error_(error::kNoError),
use_shader_translator_(true),
validators_(group_->feature_info()->validators()),
- feature_info_(group_->feature_info()),
- depth24_stencil8_oes_supported_(false) {
+ feature_info_(group_->feature_info()) {
attrib_0_value_.v[0] = 0.0f;
attrib_0_value_.v[1] = 0.0f;
attrib_0_value_.v[2] = 0.0f;
@@ -1539,6 +1714,7 @@ GLES2DecoderImpl::GLES2DecoderImpl(ContextGroup* group)
bool GLES2DecoderImpl::Initialize(gfx::GLContext* context,
const gfx::Size& size,
+ const std::vector<int32>& attribs,
GLES2Decoder* parent,
uint32 parent_client_texture_id) {
DCHECK(context);
@@ -1563,15 +1739,6 @@ bool GLES2DecoderImpl::Initialize(gfx::GLContext* context,
vertex_attrib_manager_.Initialize(group_->max_vertex_attribs());
- // Check supported extensions.
- depth24_stencil8_oes_supported_ =
- context_->HasExtension("GL_OES_packed_depth_stencil");
- if (depth24_stencil8_oes_supported_) {
- LOG(INFO) << "GL_OES_packed_depth_stencil supported.";
- } else {
- LOG(INFO) << "GL_OES_packed_depth_stencil not supported.";
- }
-
// 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.
glEnableVertexAttribArray(0);
@@ -1597,21 +1764,108 @@ bool GLES2DecoderImpl::Initialize(gfx::GLContext* context,
CHECK_GL_ERROR();
if (context_->IsOffscreen()) {
+ ContextCreationAttribParser attrib_parser;
+ if (!attrib_parser.Parse(attribs))
+ return false;
+
+ if (attrib_parser.samples_ > 0 && attrib_parser.sample_buffers_ > 0 &&
+ (feature_info_->feature_flags().ext_framebuffer_multisample ||
+ context_->HasExtension("GL_ANGLE_framebuffer_multisample"))) {
+ // Per ext_framebuffer_multisample spec, need max bound on sample count.
+ GLint max_sample_count;
+ glGetIntegerv(GL_MAX_SAMPLES_EXT, &max_sample_count);
+ offscreen_target_samples_ = std::min(attrib_parser.samples_,
+ max_sample_count);
+ } else {
+ offscreen_target_samples_ = 1;
+ }
+
+ if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2) {
+ const bool rgb8_supported =
+ context_->HasExtension("GL_OES_rgb8_rgba8");
+ // The only available default render buffer formats in GLES2 have very
+ // 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_parser.alpha_size_ > 0 ?
+ GL_RGBA8 : GL_RGB8;
+ } else {
+ offscreen_target_samples_ = 1;
+ offscreen_target_color_format_ = attrib_parser.alpha_size_ > 0 ?
+ GL_RGBA : GL_RGB;
+ }
+
+ // ANGLE only supports packed depth/stencil formats, so use it if it is
+ // available.
+ const bool depth24_stencil8_supported =
+ context_->HasExtension("GL_OES_packed_depth_stencil");
+ if (depth24_stencil8_supported) {
+ LOG(INFO) << "GL_OES_packed_depth_stencil supported.";
+ } else {
+ LOG(INFO) << "GL_OES_packed_depth_stencil not supported.";
+ }
+ if (attrib_parser.depth_size_ > 0 && depth24_stencil8_supported) {
+ offscreen_target_depth_format_ = GL_DEPTH24_STENCIL8;
+ offscreen_target_stencil_format_ = 0;
+ } else {
+ // It may be the case that this depth/stencil combination is not
+ // supported, but this will be checked later by CheckFramebufferStatus.
+ offscreen_target_depth_format_ = attrib_parser.depth_size_ > 0 ?
+ GL_DEPTH_COMPONENT16 : 0;
+ offscreen_target_stencil_format_ = attrib_parser.stencil_size_ > 0 ?
+ GL_STENCIL_INDEX8 : 0;
+ }
+ } else {
+ offscreen_target_color_format_ = attrib_parser.alpha_size_ > 0 ?
+ GL_RGBA : GL_RGB;
+
+ // If depth is requested at all, use the packed depth stencil format if
+ // it's available, as some desktop GL drivers don't support any non-packed
+ // formats for depth attachments.
+ const bool depth24_stencil8_supported =
+ context_->HasExtension("GL_EXT_packed_depth_stencil");
+ if (depth24_stencil8_supported) {
+ LOG(INFO) << "GL_EXT_packed_depth_stencil supported.";
+ } else {
+ LOG(INFO) << "GL_EXT_packed_depth_stencil not supported.";
+ }
+
+ if (attrib_parser.depth_size_ > 0 && depth24_stencil8_supported) {
+ offscreen_target_depth_format_ = GL_DEPTH24_STENCIL8;
+ offscreen_target_stencil_format_ = 0;
+ } else {
+ offscreen_target_depth_format_ = attrib_parser.depth_size_ > 0 ?
+ GL_DEPTH_COMPONENT : 0;
+ offscreen_target_stencil_format_ = attrib_parser.stencil_size_ > 0 ?
+ GL_STENCIL_INDEX : 0;
+ }
+ }
+
// Create the target frame buffer. This is the one that the client renders
// directly to.
offscreen_target_frame_buffer_.reset(new FrameBuffer(this));
offscreen_target_frame_buffer_->Create();
- offscreen_target_color_texture_.reset(new Texture(this));
- offscreen_target_color_texture_->Create();
- offscreen_target_depth_render_buffer_.reset(
- new RenderBuffer(this));
+ // Due to GLES2 format limitations, either the color texture (for
+ // non-multisampling) or the color render buffer (for multisampling) will be
+ // 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 RenderBuffer(this));
+ offscreen_target_color_render_buffer_->Create();
+ } else {
+ offscreen_target_color_texture_.reset(new Texture(this));
+ offscreen_target_color_texture_->Create();
+ }
+ offscreen_target_depth_render_buffer_.reset(new RenderBuffer(this));
offscreen_target_depth_render_buffer_->Create();
- offscreen_target_stencil_render_buffer_.reset(
- new RenderBuffer(this));
+ offscreen_target_stencil_render_buffer_.reset(new RenderBuffer(this));
offscreen_target_stencil_render_buffer_->Create();
// Create the saved offscreen texture. The target frame buffer is copied
// here when SwapBuffers is called.
+ offscreen_saved_frame_buffer_.reset(new FrameBuffer(this));
+ offscreen_saved_frame_buffer_->Create();
+ //
offscreen_saved_color_texture_.reset(new Texture(this));
offscreen_saved_color_texture_->Create();
@@ -1792,14 +2046,6 @@ void GLES2DecoderImpl::DeleteTexturesHelper(
}
}
-static bool IsAngle() {
-#if defined(OS_WIN)
- return gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2;
-#else
- return false;
-#endif
-}
-
// } // anonymous namespace
bool GLES2DecoderImpl::MakeCurrent() {
@@ -1930,70 +2176,80 @@ gfx::Size GLES2DecoderImpl::GetBoundReadFrameBufferSize() {
}
return gfx::Size(width, height);
- } else if (offscreen_target_color_texture_.get()) {
- return offscreen_target_color_texture_->size();
+ } else if (offscreen_target_frame_buffer_.get()) {
+ return offscreen_size_;
} else {
return context_->GetSize();
}
}
bool GLES2DecoderImpl::UpdateOffscreenFrameBufferSize() {
- if (offscreen_target_color_texture_->size() == pending_offscreen_size_)
+ if (offscreen_size_ == pending_offscreen_size_)
return true;
- // Reallocate the offscreen target buffers.
- if (!offscreen_target_color_texture_->AllocateStorage(
- pending_offscreen_size_)) {
- LOG(ERROR) << "GLES2DecoderImpl::UpdateOffscreenFrameBufferSize failed "
- << "to allocate storage for offscreen target buffer.";
- return false;
- }
-
- // GLES2 may only allow a combination of 16-bit depth buffers and / or 8-bit
- // stencil buffer. A packed 24/8 bit depth stencil buffer is preferred.
- // ANGLE only supports the latter, i.e. is does not support core GLES2 in
- // this respect. So we check for packed depth stencil support.
- if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2 &&
- !depth24_stencil8_oes_supported_) {
- if (!offscreen_target_depth_render_buffer_->AllocateStorage(
- pending_offscreen_size_, GL_DEPTH_COMPONENT16)) {
- LOG(ERROR) << "GLES2DecoderImpl::UpdateOffscreenFrameBufferSize failed "
- << "to allocate storage for offscreen target depth buffer.";
- return false;
- }
+ offscreen_size_ = pending_offscreen_size_;
- if (!offscreen_target_stencil_render_buffer_->AllocateStorage(
- pending_offscreen_size_, GL_STENCIL_INDEX8)) {
+ // Reallocate the offscreen target buffers.
+ DCHECK(offscreen_target_color_format_);
+ if (IsOffscreenBufferMultisampled()) {
+ if (!offscreen_target_color_render_buffer_->AllocateStorage(
+ pending_offscreen_size_, offscreen_target_color_format_,
+ offscreen_target_samples_)) {
LOG(ERROR) << "GLES2DecoderImpl::UpdateOffscreenFrameBufferSize failed "
- << "to allocate storage for offscreen target stencil buffer.";
+ << "to allocate storage for offscreen target color buffer.";
return false;
}
} else {
- if (!offscreen_target_depth_render_buffer_->AllocateStorage(
- pending_offscreen_size_, GL_DEPTH24_STENCIL8)) {
+ if (!offscreen_target_color_texture_->AllocateStorage(
+ pending_offscreen_size_, offscreen_target_color_format_)) {
LOG(ERROR) << "GLES2DecoderImpl::UpdateOffscreenFrameBufferSize failed "
- << "to allocate storage for offscreen target "
- << "depth stencil buffer.";
+ << "to allocate storage for offscreen target color texture.";
return false;
}
}
+ if (offscreen_target_depth_format_ &&
+ !offscreen_target_depth_render_buffer_->AllocateStorage(
+ pending_offscreen_size_, offscreen_target_depth_format_,
+ offscreen_target_samples_)) {
+ LOG(ERROR) << "GLES2DecoderImpl::UpdateOffscreenFrameBufferSize failed "
+ << "to allocate storage for offscreen target depth buffer.";
+ return false;
+ }
+ if (offscreen_target_stencil_format_ &&
+ !offscreen_target_stencil_render_buffer_->AllocateStorage(
+ pending_offscreen_size_, offscreen_target_stencil_format_,
+ offscreen_target_samples_)) {
+ LOG(ERROR) << "GLES2DecoderImpl::UpdateOffscreenFrameBufferSize failed "
+ << "to allocate storage for offscreen target stencil buffer.";
+ return false;
+ }
// Attach the offscreen target buffers to the target frame buffer.
- offscreen_target_frame_buffer_->AttachRenderTexture(
- offscreen_target_color_texture_.get());
- offscreen_target_frame_buffer_->AttachRenderBuffer(
- GL_DEPTH_ATTACHMENT,
- offscreen_target_depth_render_buffer_.get());
- if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2 &&
- !depth24_stencil8_oes_supported_) {
+ if (IsOffscreenBufferMultisampled()) {
offscreen_target_frame_buffer_->AttachRenderBuffer(
- GL_STENCIL_ATTACHMENT,
- offscreen_target_stencil_render_buffer_.get());
+ GL_COLOR_ATTACHMENT0,
+ offscreen_target_color_render_buffer_.get());
} else {
+ offscreen_target_frame_buffer_->AttachRenderTexture(
+ offscreen_target_color_texture_.get());
+ }
+ if (offscreen_target_depth_format_) {
+ offscreen_target_frame_buffer_->AttachRenderBuffer(
+ GL_DEPTH_ATTACHMENT,
+ offscreen_target_depth_render_buffer_.get());
+ }
+ const bool packed_depth_stencil =
+ offscreen_target_depth_format_ == GL_DEPTH24_STENCIL8;
+ if (packed_depth_stencil) {
offscreen_target_frame_buffer_->AttachRenderBuffer(
GL_STENCIL_ATTACHMENT,
offscreen_target_depth_render_buffer_.get());
+ } else if (offscreen_target_stencil_format_) {
+ offscreen_target_frame_buffer_->AttachRenderBuffer(
+ GL_STENCIL_ATTACHMENT,
+ offscreen_target_stencil_render_buffer_.get());
}
+
if (offscreen_target_frame_buffer_->CheckStatus() !=
GL_FRAMEBUFFER_COMPLETE) {
LOG(ERROR) << "GLES2DecoderImpl::UpdateOffscreenFrameBufferSize failed "
@@ -2016,10 +2272,21 @@ bool GLES2DecoderImpl::UpdateOffscreenFrameBufferSize() {
RestoreClearState();
}
- if (parent_) {
- // Adjust the saved offscreen color texture (only accessible to parent).
- offscreen_saved_color_texture_->AllocateStorage(pending_offscreen_size_);
+ if (parent_ || IsOffscreenBufferMultisampled()) {
+ offscreen_saved_color_texture_->AllocateStorage(pending_offscreen_size_,
+ GL_RGBA);
+ offscreen_saved_frame_buffer_->AttachRenderTexture(
+ offscreen_saved_color_texture_.get());
+ if (offscreen_saved_frame_buffer_->CheckStatus() !=
+ GL_FRAMEBUFFER_COMPLETE) {
+ LOG(ERROR) << "GLES2DecoderImpl::UpdateOffscreenFrameBufferSize failed "
+ << "because offscreen saved FBO was incomplete.";
+ return false;
+ }
+ }
+
+ if (parent_) {
// Update the info about the offscreen saved color texture in the parent.
// The reference to the parent is a weak pointer and will become null if the
// parent is later destroyed.
@@ -2042,32 +2309,15 @@ bool GLES2DecoderImpl::UpdateOffscreenFrameBufferSize() {
GL_RGBA,
GL_UNSIGNED_BYTE);
- // Attach the saved offscreen color texture to a frame buffer so we can
- // clear it with glClear.
- offscreen_target_frame_buffer_->AttachRenderTexture(
- offscreen_saved_color_texture_.get());
- if (offscreen_target_frame_buffer_->CheckStatus() !=
- GL_FRAMEBUFFER_COMPLETE) {
- LOG(ERROR) << "GLES2DecoderImpl::UpdateOffscreenFrameBufferSize failed "
- << "because offscreen FBO was incomplete prior ro clearing "
- << "offscreen saved texture.";
- return false;
- }
-
// Clear the offscreen color texture.
{
- ScopedFrameBufferBinder binder(this,
- offscreen_target_frame_buffer_->id());
+ ScopedFrameBufferBinder binder(this, offscreen_saved_frame_buffer_->id());
glClearColor(0, 0, 0, 0);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDisable(GL_SCISSOR_TEST);
glClear(GL_COLOR_BUFFER_BIT);
RestoreClearState();
}
-
- // Re-attach the offscreen render texture to the target frame buffer.
- offscreen_target_frame_buffer_->AttachRenderTexture(
- offscreen_target_color_texture_.get());
}
return true;
@@ -2121,6 +2371,11 @@ void GLES2DecoderImpl::Destroy() {
offscreen_target_color_texture_.reset();
}
+ if (offscreen_target_color_render_buffer_.get()) {
+ offscreen_target_color_render_buffer_->Destroy();
+ offscreen_target_color_render_buffer_.reset();
+ }
+
if (offscreen_target_depth_render_buffer_.get()) {
offscreen_target_depth_render_buffer_->Destroy();
offscreen_target_depth_render_buffer_.reset();
@@ -2131,6 +2386,11 @@ void GLES2DecoderImpl::Destroy() {
offscreen_target_stencil_render_buffer_.reset();
}
+ if (offscreen_saved_frame_buffer_.get()) {
+ offscreen_saved_frame_buffer_->Destroy();
+ offscreen_saved_frame_buffer_.reset();
+ }
+
if (offscreen_saved_color_texture_.get()) {
offscreen_saved_color_texture_->Destroy();
offscreen_saved_color_texture_.reset();
@@ -4243,6 +4503,8 @@ error::Error GLES2DecoderImpl::HandleReadPixels(
CopyRealGLErrorsToWrapper();
+ ScopedResolvedFrameBufferBinder binder(this);
+
// Get the size of the current fbo or backbuffer.
gfx::Size max_size = GetBoundReadFrameBufferSize();
@@ -4925,6 +5187,7 @@ void GLES2DecoderImpl::DoCopyTexImage2D(
// internal_format.
// TODO(gman): Type needs to match format for FBO.
CopyRealGLErrorsToWrapper();
+ ScopedResolvedFrameBufferBinder binder(this);
glCopyTexImage2D(target, level, internal_format, x, y, width, height, border);
GLenum error = glGetError();
if (error == GL_NO_ERROR) {
@@ -4960,6 +5223,7 @@ void GLES2DecoderImpl::DoCopyTexSubImage2D(
}
// TODO(gman): Should we check that x, y, width, and height are in range
// for current FBO?
+ ScopedResolvedFrameBufferBinder binder(this);
glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
}
@@ -5326,7 +5590,15 @@ error::Error GLES2DecoderImpl::HandleSwapBuffers(
return error::kLostContext;
}
- if (parent_) {
+ if (IsOffscreenBufferMultisampled()) {
+ // For multisampled buffers, bind the resolved frame buffer so that
+ // callbacks can call ReadPixels or CopyTexImage2D.
+ ScopedResolvedFrameBufferBinder binder(this);
+ if (swap_buffers_callback_.get()) {
+ swap_buffers_callback_->Run();
+ }
+ return error::kNoError;
+ } else if (parent_) {
// Copy the target frame buffer to the saved offscreen texture.
ScopedFrameBufferBinder binder(this,
offscreen_target_frame_buffer_->id());
@@ -5346,14 +5618,6 @@ error::Error GLES2DecoderImpl::HandleSwapBuffers(
}
}
- // TODO(kbr): when the back buffer is multisampled, then at least on Mac
- // OS X (and probably on all platforms, for best semantics), we will need
- // to perform the resolve step and bind the offscreen_saved_color_texture_
- // as the color attachment before calling the swap buffers callback, which
- // expects a normal (non-multisampled) frame buffer for glCopyTexImage2D /
- // glReadPixels. After the callback runs, the multisampled frame buffer
- // needs to be bound again.
-
if (swap_buffers_callback_.get()) {
swap_buffers_callback_->Run();
}
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h
index 57ec8b5..f23198e 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.h
@@ -7,6 +7,8 @@
#ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_H_
#define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_H_
+#include <vector>
+
#include "base/callback.h"
#include "build/build_config.h"
#include "gfx/size.h"
@@ -59,6 +61,7 @@ class GLES2Decoder : public CommonDecoder {
// true if successful.
virtual bool Initialize(gfx::GLContext* context,
const gfx::Size& size,
+ const std::vector<int32>& attribs,
GLES2Decoder* parent,
uint32 parent_client_texture_id) = 0;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
index af5baf5..4034f54 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
@@ -7,6 +7,8 @@
#ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_MOCK_H_
#define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_MOCK_H_
+#include <vector>
+
#include "gfx/size.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
#include "base/callback.h"
@@ -28,8 +30,9 @@ class MockGLES2Decoder : public GLES2Decoder {
.WillByDefault(testing::Return(true));
}
- MOCK_METHOD4(Initialize, bool(gfx::GLContext* context,
+ MOCK_METHOD5(Initialize, bool(gfx::GLContext* context,
const gfx::Size& size,
+ const std::vector<int32>& attribs,
GLES2Decoder* parent,
uint32 parent_texture_id));
MOCK_METHOD0(Destroy, void());
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
index c1f3c46..dcd90bd 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -101,7 +101,7 @@ void GLES2DecoderTestBase::InitDecoder(const char* extensions) {
context_ = new gfx::StubGLContext;
decoder_.reset(GLES2Decoder::Create(&group_));
- decoder_->Initialize(context_, gfx::Size(), NULL, 0);
+ decoder_->Initialize(context_, gfx::Size(), std::vector<int32>(), NULL, 0);
decoder_->set_engine(engine_.get());
EXPECT_CALL(*gl_, GenBuffersARB(_, _))
@@ -707,5 +707,3 @@ const char* GLES2DecoderWithShaderTestBase::kUniform3Name = "uniform3[0]";
} // namespace gles2
} // namespace gpu
-
-
diff --git a/gpu/command_buffer/service/gpu_processor.cc b/gpu/command_buffer/service/gpu_processor.cc
index 4bb0e64..4e8984d 100644
--- a/gpu/command_buffer/service/gpu_processor.cc
+++ b/gpu/command_buffer/service/gpu_processor.cc
@@ -39,6 +39,7 @@ GPUProcessor::~GPUProcessor() {
bool GPUProcessor::InitializeCommon(gfx::GLContext* context,
const gfx::Size& size,
+ const std::vector<int32>& attribs,
gles2::GLES2Decoder* parent_decoder,
uint32 parent_texture_id) {
DCHECK(context);
@@ -66,6 +67,7 @@ bool GPUProcessor::InitializeCommon(gfx::GLContext* context,
// Initialize the decoder with either the view or pbuffer GLContext.
if (!decoder_->Initialize(context,
size,
+ attribs,
parent_decoder,
parent_texture_id)) {
LOG(ERROR) << "GPUProcessor::InitializeCommon failed because decoder "
diff --git a/gpu/command_buffer/service/gpu_processor.h b/gpu/command_buffer/service/gpu_processor.h
index cd539bc..417f4e0 100644
--- a/gpu/command_buffer/service/gpu_processor.h
+++ b/gpu/command_buffer/service/gpu_processor.h
@@ -5,6 +5,8 @@
#ifndef GPU_COMMAND_BUFFER_SERVICE_GPU_PROCESSOR_H_
#define GPU_COMMAND_BUFFER_SERVICE_GPU_PROCESSOR_H_
+#include <vector>
+
#include "app/surface/transport_dib.h"
#include "base/callback.h"
#include "base/ref_counted.h"
@@ -46,12 +48,14 @@ class GPUProcessor : public CommandBufferEngine {
// Perform platform specific and common initialization.
bool Initialize(gfx::PluginWindowHandle hwnd,
const gfx::Size& size,
+ const std::vector<int32>& attribs,
GPUProcessor* parent,
uint32 parent_texture_id);
// Perform common initialization. Takes ownership of GLContext.
bool InitializeCommon(gfx::GLContext* context,
const gfx::Size& size,
+ const std::vector<int32>& attribs,
gles2::GLES2Decoder* parent_decoder,
uint32 parent_texture_id);
diff --git a/gpu/command_buffer/service/gpu_processor_linux.cc b/gpu/command_buffer/service/gpu_processor_linux.cc
index 67168a6..9938558 100644
--- a/gpu/command_buffer/service/gpu_processor_linux.cc
+++ b/gpu/command_buffer/service/gpu_processor_linux.cc
@@ -11,6 +11,7 @@ namespace gpu {
bool GPUProcessor::Initialize(gfx::PluginWindowHandle window,
const gfx::Size& size,
+ const std::vector<int32>& attribs,
GPUProcessor* parent,
uint32 parent_texture_id) {
// Get the parent decoder and the GLContext to share IDs with, if any.
@@ -43,6 +44,7 @@ bool GPUProcessor::Initialize(gfx::PluginWindowHandle window,
return InitializeCommon(context.release(),
size,
+ attribs,
parent_decoder,
parent_texture_id);
}
diff --git a/gpu/command_buffer/service/gpu_processor_mac.cc b/gpu/command_buffer/service/gpu_processor_mac.cc
index 8bd2fac..19d2734 100644
--- a/gpu/command_buffer/service/gpu_processor_mac.cc
+++ b/gpu/command_buffer/service/gpu_processor_mac.cc
@@ -11,6 +11,7 @@ namespace gpu {
bool GPUProcessor::Initialize(gfx::PluginWindowHandle window,
const gfx::Size& size,
+ const std::vector<int32>& attribs,
GPUProcessor* parent,
uint32 parent_texture_id) {
// Get the parent decoder and the GLContext to share IDs with, if any.
@@ -51,6 +52,7 @@ bool GPUProcessor::Initialize(gfx::PluginWindowHandle window,
return InitializeCommon(context.release(),
size,
+ attribs,
parent_decoder,
parent_texture_id);
}
@@ -98,4 +100,3 @@ void GPUProcessor::WillSwapBuffers() {
}
} // namespace gpu
-
diff --git a/gpu/command_buffer/service/gpu_processor_win.cc b/gpu/command_buffer/service/gpu_processor_win.cc
index 2df4d50..a4fd90b 100644
--- a/gpu/command_buffer/service/gpu_processor_win.cc
+++ b/gpu/command_buffer/service/gpu_processor_win.cc
@@ -13,6 +13,7 @@ namespace gpu {
bool GPUProcessor::Initialize(gfx::PluginWindowHandle window,
const gfx::Size& size,
+ const std::vector<int32>& attribs,
GPUProcessor* parent,
uint32 parent_texture_id) {
// Get the parent decoder and the GLContext to share IDs with, if any.
@@ -42,6 +43,7 @@ bool GPUProcessor::Initialize(gfx::PluginWindowHandle window,
return InitializeCommon(context.release(),
size,
+ attribs,
parent_decoder,
parent_texture_id);
}
diff --git a/gpu/demos/framework/window.cc b/gpu/demos/framework/window.cc
index 092dc1d..881452a 100644
--- a/gpu/demos/framework/window.cc
+++ b/gpu/demos/framework/window.cc
@@ -61,7 +61,8 @@ bool Window::CreateRenderContext(gfx::PluginWindowHandle hwnd) {
GPUProcessor* gpu_processor(
new GPUProcessor(command_buffer.get()));
- if (!gpu_processor->Initialize(hwnd, gfx::Size(), NULL, 0)) {
+ if (!gpu_processor->Initialize(hwnd, gfx::Size(), std::vector<int32>(),
+ NULL, 0)) {
return false;
}
@@ -91,4 +92,3 @@ bool Window::CreateRenderContext(gfx::PluginWindowHandle hwnd) {
} // namespace demos
} // namespace gpu
-