| Index: gpu/command_buffer/service/gles2_cmd_decoder.cc
|
| ===================================================================
|
| --- gpu/command_buffer/service/gles2_cmd_decoder.cc (revision 37920)
|
| +++ gpu/command_buffer/service/gles2_cmd_decoder.cc (working copy)
|
| @@ -17,9 +17,18 @@
|
| #include "gpu/command_buffer/service/cmd_buffer_engine.h"
|
| #include "gpu/command_buffer/service/gl_utils.h"
|
| #include "gpu/command_buffer/service/gles2_cmd_validation.h"
|
| -#if defined(OS_LINUX) && !defined(UNIT_TEST)
|
| +#if defined(UNIT_TEST)
|
| +#elif defined(OS_LINUX)
|
| // XWindowWrapper is stubbed out for unit-tests.
|
| #include "gpu/command_buffer/service/x_utils.h"
|
| +#elif defined(OS_MACOSX)
|
| +// The following two #includes CAN NOT go above the inclusion of
|
| +// gl_utils.h and therefore glew.h regardless of what the Google C++
|
| +// style guide says.
|
| +#include <CoreFoundation/CoreFoundation.h> // NOLINT
|
| +#include <OpenGL/OpenGL.h> // NOLINT
|
| +#include "base/scoped_cftyperef.h"
|
| +#include "chrome/common/io_surface_support_mac.h"
|
| #endif
|
|
|
| namespace gpu {
|
| @@ -38,9 +47,11 @@
|
| COMPILE_ASSERT(sizeof(GLfloat) == sizeof(float), // NOLINT
|
| GLfloat_not_same_size_as_float);
|
|
|
| -namespace {
|
| +// TODO(kbr): the use of this anonymous namespace core dumps the
|
| +// linker on Mac OS X 10.6 when the symbol ordering file is used
|
| +// namespace {
|
|
|
| -size_t GetGLTypeSize(GLenum type) {
|
| +static size_t GetGLTypeSize(GLenum type) {
|
| switch (type) {
|
| case GL_BYTE:
|
| return sizeof(GLbyte); // NOLINT
|
| @@ -147,7 +158,7 @@
|
| }
|
| }
|
|
|
| -} // anonymous namespace.
|
| +// } // anonymous namespace.
|
|
|
| #if defined(UNIT_TEST)
|
| GLES2Decoder::GLES2Decoder()
|
| @@ -551,6 +562,13 @@
|
| virtual bool MakeCurrent();
|
| virtual uint32 GetServiceIdForTesting(uint32 client_id);
|
|
|
| +#if !defined(UNIT_TEST) && defined(OS_MACOSX)
|
| + // Overridden from GLES2Decoder.
|
| + virtual uint64 SetWindowSize(int32 width, int32 height);
|
| +#endif
|
| +
|
| + virtual void SetSwapBuffersCallback(Callback0::Type* callback);
|
| +
|
| // Removes any buffers in the VertexAtrribInfos and BufferInfos. This is used
|
| // on glDeleteBuffers so we can make sure the user does not try to render
|
| // with deleted buffers.
|
| @@ -729,10 +747,25 @@
|
| #elif defined(OS_WIN)
|
| HDC device_context_;
|
| HGLRC gl_context_;
|
| +#elif defined(OS_MACOSX)
|
| + CGLContextObj gl_context_;
|
| + CGLPBufferObj pbuffer_;
|
| + scoped_cftyperef<CFTypeRef> io_surface_;
|
| + int32 surface_width_;
|
| + int32 surface_height_;
|
| + GLuint texture_;
|
| + GLuint fbo_;
|
| + GLuint depth_renderbuffer_;
|
| + // For tracking whether the default framebuffer / renderbuffer or
|
| + // ones created by the end user are currently bound
|
| + GLuint bound_fbo_;
|
| + GLuint bound_renderbuffer_;
|
| #endif
|
|
|
| bool anti_aliased_;
|
|
|
| + scoped_ptr<Callback0::Type> swap_buffers_callback_;
|
| +
|
| DISALLOW_COPY_AND_ASSIGN(GLES2DecoderImpl);
|
| };
|
|
|
| @@ -754,6 +787,16 @@
|
| #elif defined(OS_WIN)
|
| device_context_(NULL),
|
| gl_context_(NULL),
|
| +#elif defined(OS_MACOSX)
|
| + gl_context_(NULL),
|
| + pbuffer_(NULL),
|
| + surface_width_(0),
|
| + surface_height_(0),
|
| + texture_(0),
|
| + fbo_(0),
|
| + depth_renderbuffer_(0),
|
| + bound_fbo_(0),
|
| + bound_renderbuffer_(0),
|
| #endif
|
| anti_aliased_(false) {
|
| }
|
| @@ -790,7 +833,9 @@
|
| return success;
|
| }
|
|
|
| -namespace {
|
| +// TODO(kbr): the use of this anonymous namespace core dumps the
|
| +// linker on Mac OS X 10.6 when the symbol ordering file is used
|
| +// namespace {
|
|
|
| #if defined(UNIT_TEST)
|
| #elif defined(OS_WIN)
|
| @@ -1007,7 +1052,7 @@
|
| glDeleteTextures(n, ids);
|
| }
|
|
|
| -} // anonymous namespace
|
| +// } // anonymous namespace
|
|
|
| bool GLES2DecoderImpl::MakeCurrent() {
|
| #if defined(UNIT_TEST)
|
| @@ -1024,6 +1069,14 @@
|
| return true;
|
| #elif defined(OS_LINUX)
|
| return window()->MakeCurrent();
|
| +#elif defined(OS_MACOSX)
|
| + if (CGLGetCurrentContext() != gl_context_) {
|
| + if (CGLSetCurrentContext(gl_context_) != kCGLNoError) {
|
| + DLOG(ERROR) << "Unable to make gl context current.";
|
| + return false;
|
| + }
|
| + }
|
| + return true;
|
| #else
|
| NOTREACHED();
|
| return false;
|
| @@ -1103,6 +1156,49 @@
|
| DCHECK(window());
|
| if (!window()->Initialize())
|
| return false;
|
| +#elif defined(OS_MACOSX)
|
| + // Create a 1x1 pbuffer and associated context to bootstrap things
|
| + static const CGLPixelFormatAttribute attribs[] = {
|
| + (CGLPixelFormatAttribute) kCGLPFAPBuffer,
|
| + (CGLPixelFormatAttribute) 0
|
| + };
|
| + CGLPixelFormatObj pixelFormat;
|
| + GLint numPixelFormats;
|
| + if (CGLChoosePixelFormat(attribs,
|
| + &pixelFormat,
|
| + &numPixelFormats) != kCGLNoError) {
|
| + DLOG(ERROR) << "Error choosing pixel format.";
|
| + return false;
|
| + }
|
| + if (!pixelFormat) {
|
| + return false;
|
| + }
|
| + CGLContextObj context;
|
| + CGLError res = CGLCreateContext(pixelFormat, 0, &context);
|
| + CGLDestroyPixelFormat(pixelFormat);
|
| + if (res != kCGLNoError) {
|
| + DLOG(ERROR) << "Error creating context.";
|
| + return false;
|
| + }
|
| + CGLPBufferObj pbuffer;
|
| + if (CGLCreatePBuffer(1, 1,
|
| + GL_TEXTURE_2D, GL_RGBA,
|
| + 0, &pbuffer) != kCGLNoError) {
|
| + CGLDestroyContext(context);
|
| + DLOG(ERROR) << "Error creating pbuffer.";
|
| + return false;
|
| + }
|
| + if (CGLSetPBuffer(context, pbuffer, 0, 0, 0) != kCGLNoError) {
|
| + CGLDestroyContext(context);
|
| + CGLDestroyPBuffer(pbuffer);
|
| + DLOG(ERROR) << "Error attaching pbuffer to context.";
|
| + return false;
|
| + }
|
| + gl_context_ = context;
|
| + pbuffer_ = pbuffer;
|
| + // Now we're ready to handle SetWindowSize calls, which will
|
| + // allocate and/or reallocate the IOSurface and associated offscreen
|
| + // OpenGL structures for rendering.
|
| #endif
|
|
|
| return true;
|
| @@ -1164,11 +1260,141 @@
|
| return true;
|
| }
|
|
|
| +#if !defined(UNIT_TEST) && defined(OS_MACOSX)
|
| +static void AddBooleanValue(CFMutableDictionaryRef dictionary,
|
| + const CFStringRef key,
|
| + bool value) {
|
| + CFDictionaryAddValue(dictionary, key,
|
| + (value ? kCFBooleanTrue : kCFBooleanFalse));
|
| +}
|
| +
|
| +static void AddIntegerValue(CFMutableDictionaryRef dictionary,
|
| + const CFStringRef key,
|
| + int32 value) {
|
| + CFNumberRef number = CFNumberCreate(NULL, kCFNumberSInt32Type, &value);
|
| + CFDictionaryAddValue(dictionary, key, number);
|
| +}
|
| +
|
| +uint64 GLES2DecoderImpl::SetWindowSize(int32 width, int32 height) {
|
| + if (surface_width_ == width && surface_height_ == height) {
|
| + // Return 0 to indicate to the caller that no new backing store
|
| + // allocation occurred.
|
| + return 0;
|
| + }
|
| +
|
| + IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize();
|
| + if (!io_surface_support)
|
| + return 0;
|
| +
|
| + if (!MakeCurrent())
|
| + return 0;
|
| +
|
| + // GL_TEXTURE_RECTANGLE_ARB is the best supported render target on
|
| + // Mac OS X and is required for IOSurface interoperability.
|
| + GLenum target = GL_TEXTURE_RECTANGLE_ARB;
|
| +
|
| + if (!texture_) {
|
| + // Generate the texture object.
|
| + glGenTextures(1, &texture_);
|
| + glBindTexture(target, texture_);
|
| + glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
| + glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
| + // Generate and bind the framebuffer object.
|
| + glGenFramebuffersEXT(1, &fbo_);
|
| + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_);
|
| + bound_fbo_ = fbo_;
|
| + // Generate (but don't bind) the depth buffer -- we don't need
|
| + // this bound in order to do offscreen rendering.
|
| + glGenRenderbuffersEXT(1, &depth_renderbuffer_);
|
| + }
|
| +
|
| + // Allocate a new IOSurface, which is the GPU resource that can be
|
| + // shared across processes.
|
| + scoped_cftyperef<CFMutableDictionaryRef> properties;
|
| + properties.reset(CFDictionaryCreateMutable(kCFAllocatorDefault,
|
| + 0,
|
| + &kCFTypeDictionaryKeyCallBacks,
|
| + &kCFTypeDictionaryValueCallBacks));
|
| + AddIntegerValue(properties,
|
| + io_surface_support->GetKIOSurfaceWidth(), width);
|
| + AddIntegerValue(properties,
|
| + io_surface_support->GetKIOSurfaceHeight(), height);
|
| + AddIntegerValue(properties,
|
| + io_surface_support->GetKIOSurfaceBytesPerElement(), 4);
|
| + AddBooleanValue(properties,
|
| + io_surface_support->GetKIOSurfaceIsGlobal(), true);
|
| + // I believe we should be able to unreference the IOSurfaces without
|
| + // synchronizing with the browser process because they are
|
| + // ultimately reference counted by the operating system.
|
| + io_surface_.reset(io_surface_support->IOSurfaceCreate(properties));
|
| +
|
| + // Reallocate the depth buffer.
|
| + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depth_renderbuffer_);
|
| + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,
|
| + GL_DEPTH_COMPONENT,
|
| + width,
|
| + height);
|
| + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, bound_renderbuffer_);
|
| +
|
| + // Reallocate the texture object.
|
| + glBindTexture(target, texture_);
|
| + // Don't think we need to identify a plane.
|
| + GLuint plane = 0;
|
| + io_surface_support->CGLTexImageIOSurface2D(gl_context_,
|
| + target,
|
| + GL_RGBA,
|
| + width,
|
| + height,
|
| + GL_BGRA,
|
| + GL_UNSIGNED_INT_8_8_8_8_REV,
|
| + io_surface_.get(),
|
| + plane);
|
| +
|
| + // Set up the frame buffer object.
|
| + if (bound_fbo_ != fbo_) {
|
| + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_);
|
| + }
|
| + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
|
| + GL_COLOR_ATTACHMENT0_EXT,
|
| + target,
|
| + texture_,
|
| + 0);
|
| + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
|
| + GL_DEPTH_ATTACHMENT_EXT,
|
| + GL_RENDERBUFFER_EXT,
|
| + depth_renderbuffer_);
|
| + if (bound_fbo_ != fbo_) {
|
| + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, bound_fbo_);
|
| + }
|
| +
|
| + surface_width_ = width;
|
| + surface_height_ = height;
|
| +
|
| + // Now send back an identifier for the IOSurface. We originally
|
| + // intended to send back a mach port from IOSurfaceCreateMachPort
|
| + // but it looks like Chrome IPC would need to be modified to
|
| + // properly send mach ports between processes. For the time being we
|
| + // make our IOSurfaces global and send back their identifiers. On
|
| + // the browser process side the identifier is reconstituted into an
|
| + // IOSurface for on-screen rendering.
|
| + return io_surface_support->IOSurfaceGetID(io_surface_);
|
| +}
|
| +#endif // !defined(UNIT_TEST) && defined(OS_MACOSX)
|
| +
|
| +void GLES2DecoderImpl::SetSwapBuffersCallback(Callback0::Type* callback) {
|
| + swap_buffers_callback_.reset(callback);
|
| +}
|
| +
|
| void GLES2DecoderImpl::Destroy() {
|
| #if defined(UNIT_TEST)
|
| #elif defined(OS_LINUX)
|
| DCHECK(window());
|
| window()->Destroy();
|
| +#elif defined(OS_MACOSX)
|
| + if (gl_context_)
|
| + CGLDestroyContext(gl_context_);
|
| + if (pbuffer_)
|
| + CGLDestroyPBuffer(pbuffer_);
|
| #endif
|
| }
|
|
|
| @@ -1332,7 +1558,18 @@
|
| #elif defined(OS_LINUX)
|
| DCHECK(window());
|
| window()->SwapBuffers();
|
| +#elif defined(OS_MACOSX)
|
| + if (bound_fbo_ == fbo_) {
|
| + // Bind and unbind the framebuffer to make changes to the
|
| + // IOSurface show up in the other process.
|
| + glFlush();
|
| + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
| + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_);
|
| + }
|
| #endif
|
| + if (swap_buffers_callback_.get()) {
|
| + swap_buffers_callback_->Run();
|
| + }
|
| }
|
|
|
| void GLES2DecoderImpl::DoUseProgram(GLuint program) {
|
| @@ -1476,7 +1713,9 @@
|
| return error::kNoError;
|
| }
|
|
|
| -namespace {
|
| +// TODO(kbr): the use of this anonymous namespace core dumps the
|
| +// linker on Mac OS X 10.6 when the symbol ordering file is used
|
| +// namespace {
|
|
|
| // Calls glShaderSource for the various versions of the ShaderSource command.
|
| // Assumes that data / data_size points to a piece of memory that is in range
|
| @@ -1505,7 +1744,7 @@
|
| return error::kNoError;
|
| }
|
|
|
| -} // anonymous namespace.
|
| +// } // anonymous namespace.
|
|
|
| error::Error GLES2DecoderImpl::HandleShaderSource(
|
| uint32 immediate_data_size, const gles2::ShaderSource& c) {
|
|
|