Index: webkit/api/src/GraphicsContext3D.cpp |
=================================================================== |
--- webkit/api/src/GraphicsContext3D.cpp (revision 27788) |
+++ webkit/api/src/GraphicsContext3D.cpp (working copy) |
@@ -63,8 +63,24 @@ |
#include "GL/glew.h" |
+#if PLATFORM(CG) |
+#include "GraphicsContext.h" |
+#include <CoreGraphics/CGContext.h> |
+#include <CoreGraphics/CGBitmapContext.h> |
+#include <CoreGraphics/CGImage.h> |
+#include <OpenGL/OpenGL.h> |
+#else |
+#define FLIP_FRAMEBUFFER_VERTICALLY |
+#endif |
+ |
+#if PLATFORM(SKIA) |
#include "NativeImageSkia.h" |
+#endif |
+#if PLATFORM(DARWIN) |
+#define USE_TEXTURE_RECTANGLE_FOR_FRAMEBUFFER |
+#endif |
+ |
using namespace std; |
namespace WebCore { |
@@ -100,13 +116,8 @@ |
void bindTexture(unsigned long target, |
CanvasTexture* texture); |
void bufferDataImpl(unsigned long target, int size, const void* data, unsigned long usage); |
- void colorMask(bool red, bool green, bool blue, bool alpha); |
- void depthMask(bool flag); |
- void disable(unsigned long cap); |
void disableVertexAttribArray(unsigned long index); |
- void enable(unsigned long cap); |
void enableVertexAttribArray(unsigned long index); |
- void useProgram(CanvasProgram* program); |
void vertexAttribPointer(unsigned long indx, int size, int type, bool normalized, |
unsigned long stride, unsigned long offset); |
void viewportImpl(long x, long y, unsigned long width, unsigned long height); |
@@ -115,20 +126,18 @@ |
unsigned int m_texture; |
unsigned int m_fbo; |
unsigned int m_depthBuffer; |
+ unsigned int m_cachedWidth, m_cachedHeight; |
- // Objects for flipping the render output vertically |
- unsigned int m_altTexture; |
- unsigned int m_quadVBO; |
- unsigned int m_quadProgram; |
- unsigned int m_quadTexLocation; |
+#ifdef FLIP_FRAMEBUFFER_VERTICALLY |
+ unsigned char* m_scanline; |
+ void flipVertically(unsigned char* framebuffer, |
+ unsigned int width, |
+ unsigned int height); |
+#endif |
- // Storage for saving/restoring buffer, vertex attribute, |
- // blending, and program state when drawing flipped quad |
- unsigned int m_currentProgram; |
- bool m_blendEnabled; |
- bool m_depthTestEnabled; |
- bool m_depthMaskEnabled; |
- bool m_colorMask[4]; |
+ // Note: we aren't currently using this information, but we will |
+ // need to in order to verify that all enabled vertex arrays have |
+ // a valid buffer bound -- to avoid crashes on certain cards. |
unsigned int m_boundArrayBuffer; |
class VertexAttribPointerState { |
public: |
@@ -143,22 +152,21 @@ |
unsigned long stride; |
unsigned long offset; |
}; |
- VertexAttribPointerState m_vertexAttribPointerState[1]; |
- unsigned int m_activeTextureUnit; |
- class TextureUnitState { |
- public: |
- TextureUnitState(); |
- unsigned long target; |
- unsigned int texture; |
+ enum { |
+ NumTrackedPointerStates = 2 |
}; |
- TextureUnitState m_textureUnitState[1]; |
- int m_viewport[4]; |
+ VertexAttribPointerState m_vertexAttribPointerState[NumTrackedPointerStates]; |
#if PLATFORM(WIN_OS) |
HWND m_canvasWindow; |
HDC m_canvasDC; |
HGLRC m_contextObj; |
+#elif PLATFORM(CG) |
+ CGLPBufferObj m_pbuffer; |
+ CGLContextObj m_contextObj; |
+ unsigned char* m_renderOutput; |
+ CGContextRef m_cgContext; |
#else |
#error Must port GraphicsContext3D to your platform |
#endif |
@@ -176,38 +184,27 @@ |
{ |
} |
-GraphicsContext3DInternal::TextureUnitState::TextureUnitState() |
- : target(0) |
- , texture(0) |
-{ |
-} |
- |
GraphicsContext3DInternal::GraphicsContext3DInternal() |
: m_texture(0) |
, m_fbo(0) |
, m_depthBuffer(0) |
- , m_altTexture(0) |
- , m_quadVBO(0) |
- , m_quadProgram(0) |
- , m_quadTexLocation(0) |
- , m_currentProgram(0) |
- , m_blendEnabled(false) |
- , m_depthTestEnabled(false) |
- , m_depthMaskEnabled(true) |
+#ifdef FLIP_FRAMEBUFFER_VERTICALLY |
+ , m_scanline(NULL) |
+#endif |
, m_boundArrayBuffer(0) |
- , m_activeTextureUnit(0) |
#if PLATFORM(WIN_OS) |
, m_canvasWindow(NULL) |
, m_canvasDC(NULL) |
, m_contextObj(NULL) |
+#elif PLATFORM(CG) |
+ , m_pbuffer(NULL) |
+ , m_contextObj(NULL) |
+ , m_renderOutput(NULL) |
+ , m_cgContext(NULL) |
#else |
#error Must port to your platform |
#endif |
{ |
- for (int i = 0; i < 4; i++) { |
- m_viewport[i] = 0; |
- m_colorMask[i] = true; |
- } |
#if PLATFORM(WIN_OS) |
WNDCLASS wc; |
if (!GetClassInfo(GetModuleHandle(NULL), L"CANVASGL", &wc)) { |
@@ -277,12 +274,59 @@ |
setSwapInterval(1); |
#endif // RENDER_TO_DEBUGGING_WINDOW |
+#elif PLATFORM(CG) |
+ // Create a 1x1 pbuffer and associated context to bootstrap things |
+ CGLPixelFormatAttribute attribs[] = { |
+ (CGLPixelFormatAttribute) kCGLPFAPBuffer, |
+ (CGLPixelFormatAttribute) 0 |
+ }; |
+ CGLPixelFormatObj pixelFormat; |
+ GLint numPixelFormats; |
+ if (CGLChoosePixelFormat(attribs, &pixelFormat, &numPixelFormats) != kCGLNoError) { |
+ printf("GraphicsContext3D: error choosing pixel format\n"); |
+ return; |
+ } |
+ if (pixelFormat == NULL) { |
+ printf("GraphicsContext3D: no pixel format selected\n"); |
+ return; |
+ } |
+ CGLContextObj context; |
+ CGLError res = CGLCreateContext(pixelFormat, NULL, &context); |
+ CGLDestroyPixelFormat(pixelFormat); |
+ if (res != kCGLNoError) { |
+ printf("GraphicsContext3D: error creating context\n"); |
+ return; |
+ } |
+ CGLPBufferObj pbuffer; |
+ if (CGLCreatePBuffer(1, 1, GL_TEXTURE_2D, GL_RGBA, 0, &pbuffer) != kCGLNoError) { |
+ CGLDestroyContext(context); |
+ printf("GraphicsContext3D: error creating pbuffer\n"); |
+ return; |
+ } |
+ if (CGLSetPBuffer(context, pbuffer, 0, 0, 0) != kCGLNoError) { |
+ CGLDestroyContext(context); |
+ CGLDestroyPBuffer(pbuffer); |
+ printf("GraphicsContext3D: error attaching pbuffer to context\n"); |
+ return; |
+ } |
+ if (CGLSetCurrentContext(context) != kCGLNoError) { |
+ CGLDestroyContext(context); |
+ CGLDestroyPBuffer(pbuffer); |
+ printf("GraphicsContext3D: error making context current\n"); |
+ return; |
+ } |
+ m_pbuffer = pbuffer; |
+ m_contextObj = context; |
#else |
#error Must port to your platform |
#endif |
// Initialize GLEW and check for GL 2.0 support by the drivers. |
GLenum glewInitResult = glewInit(); |
+ if (glewInitResult != GLEW_OK) { |
+ printf("GraphicsContext3D: GLEW initialization failed\n"); |
+ return; |
+ } |
if (!glewIsSupported("GL_VERSION_2_0")) { |
printf("GraphicsContext3D: OpenGL 2.0 not supported\n"); |
return; |
@@ -295,7 +339,10 @@ |
#ifndef RENDER_TO_DEBUGGING_WINDOW |
glDeleteRenderbuffersEXT(1, &m_depthBuffer); |
glDeleteTextures(1, &m_texture); |
- glDeleteTextures(1, &m_altTexture); |
+#ifdef FLIP_FRAMEBUFFER_VERTICALLY |
+ if (m_scanline != NULL) |
+ delete[] m_scanline; |
+#endif |
glDeleteFramebuffersEXT(1, &m_fbo); |
#endif // !RENDER_TO_DEBUGGING_WINDOW |
#if PLATFORM(WIN_OS) |
@@ -303,6 +350,14 @@ |
wglDeleteContext(m_contextObj); |
ReleaseDC(m_canvasWindow, m_canvasDC); |
DestroyWindow(m_canvasWindow); |
+#elif PLATFORM(CG) |
+ CGLSetCurrentContext(NULL); |
+ CGLDestroyContext(m_contextObj); |
+ CGLDestroyPBuffer(m_pbuffer); |
+ if (m_cgContext != NULL) |
+ CGContextRelease(m_cgContext); |
+ if (m_renderOutput != NULL) |
+ delete[] m_renderOutput; |
#else |
#error Must port to your platform |
#endif |
@@ -315,7 +370,7 @@ |
// will need to throw an exception on error. |
GLenum error = glGetError(); |
if (error != GL_NO_ERROR) { |
- printf("GL Error : %x\n", error); |
+ printf("GraphicsContext3DInternal: GL Error : %x\n", error); |
notImplemented(); |
} |
} |
@@ -326,6 +381,10 @@ |
if (wglGetCurrentContext() != m_contextObj) |
if (wglMakeCurrent(m_canvasDC, m_contextObj)) |
return true; |
+#elif PLATFORM(CG) |
+ if (CGLGetCurrentContext() != m_contextObj) |
+ if (CGLSetCurrentContext(m_contextObj) == kCGLNoError) |
+ return true; |
#else |
#error Must port to your platform |
#endif |
@@ -342,13 +401,13 @@ |
return m_texture; |
} |
-static int createTextureObject() |
+static int createTextureObject(GLenum target) |
{ |
GLuint texture = 0; |
glGenTextures(1, &texture); |
- glBindTexture(GL_TEXTURE_2D, texture); |
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
+ glBindTexture(target, texture); |
+ glTexParameterf(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
+ glTexParameterf(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
return texture; |
} |
@@ -360,36 +419,38 @@ |
ShowWindow(m_canvasWindow, SW_SHOW); |
#endif |
+ m_cachedWidth = width; |
+ m_cachedHeight = height; |
makeContextCurrent(); |
#ifndef RENDER_TO_DEBUGGING_WINDOW |
+#ifdef USE_TEXTURE_RECTANGLE_FOR_FRAMEBUFFER |
+ // GL_TEXTURE_RECTANGLE_ARB is the best supported render target on Mac OS X |
+ GLenum target = GL_TEXTURE_RECTANGLE_ARB; |
+#else |
+ GLenum target = GL_TEXTURE_2D; |
+#endif |
if (m_texture == 0) { |
- // Generate the texture objects |
- m_texture = createTextureObject(); |
- m_altTexture = createTextureObject(); |
- |
+ // Generate the texture object |
+ m_texture = createTextureObject(target); |
// Generate the framebuffer object |
glGenFramebuffersEXT(1, &m_fbo); |
- |
// Generate the depth buffer |
glGenRenderbuffersEXT(1, &m_depthBuffer); |
- |
checkError(); |
} |
// Reallocate the color and depth buffers |
- glBindTexture(GL_TEXTURE_2D, m_texture); |
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); |
- glBindTexture(GL_TEXTURE_2D, m_altTexture); |
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); |
- glBindTexture(GL_TEXTURE_2D, 0); |
+ glBindTexture(target, m_texture); |
+ glTexImage2D(target, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); |
+ glBindTexture(target, 0); |
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo); |
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthBuffer); |
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, width, height); |
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); |
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_texture, 0); |
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, target, m_texture, 0); |
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthBuffer); |
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); |
if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { |
@@ -398,12 +459,63 @@ |
// FIXME: cleanup. |
notImplemented(); |
} |
-#endif // RENDER_TO_DEBUGGING_WINDOW |
+#endif // RENDER_TO_DEBUGGING_WINDOW |
+#ifdef FLIP_FRAMEBUFFER_VERTICALLY |
+ if (m_scanline != NULL) { |
+ delete[] m_scanline; |
+ m_scanline = NULL; |
+ } |
+ m_scanline = new unsigned char[width * 4]; |
+#endif // FLIP_FRAMEBUFFER_VERTICALLY |
+ |
glClear(GL_COLOR_BUFFER_BIT); |
viewportImpl(0, 0, width, height); |
+ |
+#if PLATFORM(CG) |
+ // Need to reallocate the client-side backing store. |
+ // FIXME: make this more efficient. |
+ if (m_cgContext != NULL) { |
+ CGContextRelease(m_cgContext); |
+ m_cgContext = NULL; |
+ } |
+ if (m_renderOutput != NULL) { |
+ delete[] m_renderOutput; |
+ m_renderOutput = NULL; |
+ } |
+ int rowBytes = width * 4; |
+ m_renderOutput = new unsigned char[height * rowBytes]; |
+ CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); |
+ m_cgContext = CGBitmapContextCreate(m_renderOutput, width, height, 8, rowBytes, |
+ colorSpace, kCGImageAlphaPremultipliedLast); |
+ CGColorSpaceRelease(colorSpace); |
+#endif // PLATFORM(CG) |
} |
+#ifdef FLIP_FRAMEBUFFER_VERTICALLY |
+void GraphicsContext3DInternal::flipVertically(unsigned char* framebuffer, |
+ unsigned int width, |
+ unsigned int height) |
+{ |
+ unsigned char* scanline = m_scanline; |
+ if (scanline == NULL) |
+ return; |
+ unsigned int rowBytes = width * 4; |
+ unsigned int count = height / 2; |
+ for (unsigned int i = 0; i < count; i++) { |
+ unsigned char* rowA = framebuffer + i * rowBytes; |
+ unsigned char* rowB = framebuffer + (height - i - 1) * rowBytes; |
+ // FIXME: this is where the multiplication of the alpha |
+ // channel into the color buffer will need to occur if the |
+ // user specifies the "premultiplyAlpha" flag in the context |
+ // creation attributes. |
+ memcpy(scanline, rowB, rowBytes); |
+ memcpy(rowB, rowA, rowBytes); |
+ memcpy(rowA, scanline, rowBytes); |
+ } |
+} |
+#endif |
+ |
void GraphicsContext3DInternal::beginPaint(CanvasRenderingContext3D* context) |
{ |
makeContextCurrent(); |
@@ -411,124 +523,61 @@ |
#ifdef RENDER_TO_DEBUGGING_WINDOW |
SwapBuffers(m_canvasDC); |
#else |
- if (m_quadVBO == 0) { |
- // Prepare necessary objects for rendering. |
- glGenBuffers(1, &m_quadVBO); |
- GLfloat vertices[] = {-1.0f, -1.0f, |
- 1.0f, -1.0f, |
- 1.0f, 1.0f, |
- -1.0f, -1.0f, |
- 1.0f, 1.0f, |
- -1.0f, 1.0f}; |
- glBindBuffer(GL_ARRAY_BUFFER, m_quadVBO); |
- glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); |
- // Vertex shader does vertical flip. |
- const GLchar* vertexShaderSrc = |
- "attribute vec2 g_Position;\n" |
- "varying vec2 texCoord;\n" |
- "void main()\n" |
- "{\n" |
- " texCoord = vec2((g_Position.x + 1.0) * 0.5,\n" |
- " (1.0 - g_Position.y) * 0.5);\n" |
- " gl_Position = vec4(g_Position, 0.0, 1.0);\n" |
- "}\n"; |
- // Fragment shader does optional premultiplication of alpha |
- // into color channels. |
- const GLchar* fragmentShaderNoPremultSrc = |
- "varying vec2 texCoord;\n" |
- "uniform sampler2D texSampler;\n" |
- "void main()\n" |
- "{\n" |
- " gl_FragColor = texture2D(texSampler, texCoord);\n" |
- "}\n"; |
- const GLchar* fragmentShaderPremultSrc = |
- "varying vec2 texCoord;\n" |
- "uniform sampler2D texSampler;\n" |
- "void main()\n" |
- "{\n" |
- " vec4 color = texture2D(texSampler, texCoord);\n" |
- " gl_FragColor = vec4(color.r * color.a,\n" |
- " color.g * color.a,\n" |
- " color.b * color.a,\n" |
- " color.a);\n" |
- "}\n"; |
- GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); |
- glShaderSource(vertexShader, 1, &vertexShaderSrc, NULL); |
- checkError(); |
- GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); |
- // FIXME: hook up fragmentShaderPremultSrc based on canvas |
- // context attributes. |
- glShaderSource(fragmentShader, 1, &fragmentShaderNoPremultSrc, NULL); |
- checkError(); |
- m_quadProgram = glCreateProgram(); |
- glAttachShader(m_quadProgram, vertexShader); |
- glAttachShader(m_quadProgram, fragmentShader); |
- glBindAttribLocation(m_quadProgram, 0, "g_Position"); |
- glLinkProgram(m_quadProgram); |
- checkError(); |
- glDeleteShader(vertexShader); |
- glDeleteShader(fragmentShader); |
- m_quadTexLocation = glGetUniformLocation(m_quadProgram, "texSampler"); |
- checkError(); |
- } |
+ // Earlier versions of this code used the GPU to flip the |
+ // framebuffer vertically before reading it back for compositing |
+ // via software. This code was quite complicated, used a lot of |
+ // GPU memory, and didn't provide an obvious speedup. Since this |
+ // vertical flip is only a temporary solution anyway until Chrome |
+ // is fully GPU composited, it wasn't worth the complexity. |
- // We've just rendered a frame into m_texture. Bind m_altTexture |
- // as the framebuffer texture, and draw m_texture on to a quad, |
- // flipping it vertically and performing alpha premultiplication |
- // and color channel swizzling. Then read back the FBO. |
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_altTexture, 0); |
- glUseProgram(m_quadProgram); |
- glActiveTexture(GL_TEXTURE0); |
- glBindTexture(GL_TEXTURE_2D, m_texture); |
- glUniform1i(m_quadTexLocation, 0); |
- glBindBuffer(GL_ARRAY_BUFFER, m_quadVBO); |
- glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, 0); |
- glEnableVertexAttribArray(0); |
- glDisable(GL_DEPTH_TEST); |
- glDisable(GL_BLEND); |
- glDepthMask(false); |
- glColorMask(true, true, true, true); |
- |
HTMLCanvasElement* canvas = context->canvas(); |
ImageBuffer* imageBuffer = canvas->buffer(); |
+ unsigned char* pixels = NULL; |
+#if PLATFORM(SKIA) |
const SkBitmap& bitmap = *imageBuffer->context()->platformContext()->bitmap(); |
ASSERT(bitmap.config() == SkBitmap::kARGB_8888_Config); |
- glViewport(0, 0, bitmap.width(), bitmap.height()); |
+ ASSERT(bitmap.width() == m_cachedWidth); |
+ ASSERT(bitmap.height() == m_cachedHeight); |
- glDrawArrays(GL_TRIANGLES, 0, 6); |
- |
// Read back the frame buffer. |
SkAutoLockPixels bitmapLock(bitmap); |
- glReadPixels(0, 0, bitmap.width(), bitmap.height(), GL_BGRA, GL_UNSIGNED_BYTE, bitmap.getPixels()); |
+ pixels = static_cast<unsigned char*>(bitmap.getPixels()); |
+ glReadPixels(0, 0, m_cachedWidth, m_cachedHeight, GL_BGRA, GL_UNSIGNED_BYTE, pixels); |
+#elif PLATFORM(CG) |
+ if (m_renderOutput != NULL) { |
+ ASSERT(CGBitmapContextGetWidth(m_cgContext) == m_cachedWidth); |
+ ASSERT(CGBitmapContextGetHeight(m_cgContext) == m_cachedHeight); |
+ pixels = m_renderOutput; |
+ glReadPixels(0, 0, m_cachedWidth, m_cachedHeight, GL_RGBA, GL_UNSIGNED_BYTE, pixels); |
+ } |
+#else |
+#error Must port to your platform |
+#endif |
- // Restore the previous FBO state. |
- glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_texture, 0); |
+#ifdef FLIP_FRAMEBUFFER_VERTICALLY |
+ if (pixels != NULL) |
+ flipVertically(pixels, m_cachedWidth, m_cachedHeight); |
+#endif |
- // Restore the user's OpenGL state. |
- glUseProgram(m_currentProgram); |
- const VertexAttribPointerState& state = m_vertexAttribPointerState[0]; |
- if (state.buffer) { |
- glBindBuffer(GL_ARRAY_BUFFER, state.buffer); |
- glVertexAttribPointer(state.indx, state.size, state.type, state.normalized, |
- state.stride, reinterpret_cast<void*>(static_cast<intptr_t>(state.offset))); |
+#if PLATFORM(SKIA) |
+ // No further work necessary |
+#elif PLATFORM(CG) |
+ if (m_renderOutput != NULL) { |
+ CGImageRef cgImage = CGBitmapContextCreateImage(m_cgContext); |
+ CGRect rect = CGRectMake(0, 0, m_cachedWidth, m_cachedHeight); |
+ // We want to completely overwrite the previous frame's |
+ // rendering results. |
+ CGContextSetBlendMode(imageBuffer->context()->platformContext(), |
+ kCGBlendModeCopy); |
+ CGContextDrawImage(imageBuffer->context()->platformContext(), |
+ rect, cgImage); |
+ CGImageRelease(cgImage); |
} |
- glBindBuffer(GL_ARRAY_BUFFER, m_boundArrayBuffer); |
- if (state.enabled) |
- glEnableVertexAttribArray(0); |
- else |
- glDisableVertexAttribArray(0); |
- const TextureUnitState& texState = m_textureUnitState[0]; |
- glBindTexture(texState.target, texState.texture); |
- glActiveTexture(m_activeTextureUnit); |
- if (m_blendEnabled) |
- glEnable(GL_BLEND); |
- if (m_depthTestEnabled) |
- glEnable(GL_DEPTH_TEST); |
- glDepthMask(m_depthMaskEnabled); |
- glColorMask(m_colorMask[0], m_colorMask[1], m_colorMask[2], m_colorMask[3]); |
- glViewport(m_viewport[0], m_viewport[1], |
- m_viewport[2], m_viewport[3]); |
-#endif // RENDER_TO_DEBUGGING_WINDOW |
+#else |
+#error Must port to your platform |
+#endif |
+ |
+#endif // RENDER_TO_DEBUGGING_WINDOW |
} |
bool GraphicsContext3DInternal::validateTextureTarget(int target) |
@@ -553,7 +602,6 @@ |
return; |
makeContextCurrent(); |
- m_activeTextureUnit = texture; |
glActiveTexture(texture); |
} |
@@ -576,12 +624,6 @@ |
makeContextCurrent(); |
unsigned int textureObject = EXTRACT(texture); |
- if (m_activeTextureUnit == 0) { |
- TextureUnitState& state = m_textureUnitState[m_activeTextureUnit]; |
- state.target = target; |
- state.texture = textureObject; |
- } |
- |
glBindTexture(target, textureObject); |
// FIXME: GL_TEXTURE_WRAP_R isn't exposed in the OpenGL ES 2.0 |
@@ -620,75 +662,23 @@ |
usage); |
} |
-void GraphicsContext3DInternal::colorMask(bool red, bool green, bool blue, bool alpha) |
-{ |
- makeContextCurrent(); |
- m_colorMask[0] = red; |
- m_colorMask[1] = green; |
- m_colorMask[2] = blue; |
- m_colorMask[3] = alpha; |
- glColorMask(red, green, blue, alpha); |
-} |
- |
-void GraphicsContext3DInternal::depthMask(bool flag) |
-{ |
- makeContextCurrent(); |
- m_depthMaskEnabled = flag; |
- glDepthMask(flag); |
-} |
- |
-void GraphicsContext3DInternal::disable(unsigned long cap) |
-{ |
- makeContextCurrent(); |
- switch (cap) { |
- case GL_BLEND: |
- m_blendEnabled = false; |
- case GL_DEPTH_TEST: |
- m_depthTestEnabled = false; |
- default: |
- break; |
- } |
- glDisable(cap); |
-} |
- |
void GraphicsContext3DInternal::disableVertexAttribArray(unsigned long index) |
{ |
makeContextCurrent(); |
- if (index == 0) { |
- m_vertexAttribPointerState[0].enabled = false; |
+ if (index < NumTrackedPointerStates) { |
+ m_vertexAttribPointerState[index].enabled = false; |
} |
glDisableVertexAttribArray(index); |
} |
-void GraphicsContext3DInternal::enable(unsigned long cap) |
-{ |
- makeContextCurrent(); |
- switch (cap) { |
- case GL_BLEND: |
- m_blendEnabled = true; |
- case GL_DEPTH_TEST: |
- m_depthTestEnabled = true; |
- default: |
- break; |
- } |
- glEnable(cap); |
-} |
- |
void GraphicsContext3DInternal::enableVertexAttribArray(unsigned long index) |
{ |
makeContextCurrent(); |
- if (index == 0) |
- m_vertexAttribPointerState[0].enabled = true; |
+ if (index < NumTrackedPointerStates) |
+ m_vertexAttribPointerState[index].enabled = true; |
glEnableVertexAttribArray(index); |
} |
-void GraphicsContext3DInternal::useProgram(CanvasProgram* program) |
-{ |
- makeContextCurrent(); |
- m_currentProgram = EXTRACT(program); |
- glUseProgram(m_currentProgram); |
-} |
- |
void GraphicsContext3DInternal::vertexAttribPointer(unsigned long indx, int size, int type, bool normalized, |
unsigned long stride, unsigned long offset) |
{ |
@@ -700,8 +690,8 @@ |
return; |
} |
- if (indx == 0) { |
- VertexAttribPointerState& state = m_vertexAttribPointerState[0]; |
+ if (indx < NumTrackedPointerStates) { |
+ VertexAttribPointerState& state = m_vertexAttribPointerState[indx]; |
state.buffer = m_boundArrayBuffer; |
state.indx = indx; |
state.size = size; |
@@ -717,108 +707,102 @@ |
void GraphicsContext3DInternal::viewportImpl(long x, long y, unsigned long width, unsigned long height) |
{ |
- m_viewport[0] = x; |
- m_viewport[1] = y; |
- m_viewport[2] = width; |
- m_viewport[3] = height; |
glViewport(x, y, width, height); |
} |
// GraphicsContext3D ----------------------------------------------------- |
-#define GRAPHICS_CONTEXT_NAME GraphicsContext3D |
- |
/* Helper macros for when we're just wrapping a gl method, so that |
* we can avoid having to type this 500 times. Note that these MUST |
* NOT BE USED if we need to check any of the parameters. |
*/ |
#define GL_SAME_METHOD_0(glname, name) \ |
-void GRAPHICS_CONTEXT_NAME::##name() \ |
+void GraphicsContext3D::name() \ |
{ \ |
makeContextCurrent(); gl##glname(); \ |
} |
#define GL_SAME_METHOD_1(glname, name, t1) \ |
-void GRAPHICS_CONTEXT_NAME::##name(t1 a1) \ |
+void GraphicsContext3D::name(t1 a1) \ |
{ \ |
makeContextCurrent(); gl##glname(a1); \ |
} |
#define GL_SAME_METHOD_1_X(glname, name, t1) \ |
-void GRAPHICS_CONTEXT_NAME::##name(t1 a1) \ |
+void GraphicsContext3D::name(t1 a1) \ |
{ \ |
makeContextCurrent(); gl##glname(EXTRACT(a1)); \ |
} |
#define GL_SAME_METHOD_2(glname, name, t1, t2) \ |
-void GRAPHICS_CONTEXT_NAME::##name(t1 a1, t2 a2) \ |
+void GraphicsContext3D::name(t1 a1, t2 a2) \ |
{ \ |
makeContextCurrent(); gl##glname(a1,a2); \ |
} |
#define GL_SAME_METHOD_2_X12(glname, name, t1, t2) \ |
-void GRAPHICS_CONTEXT_NAME::##name(t1 a1, t2 a2) \ |
+void GraphicsContext3D::name(t1 a1, t2 a2) \ |
{ \ |
makeContextCurrent(); gl##glname(EXTRACT(a1),EXTRACT(a2)); \ |
} |
#define GL_SAME_METHOD_2_X2(glname, name, t1, t2) \ |
-void GRAPHICS_CONTEXT_NAME::##name(t1 a1, t2 a2) \ |
+void GraphicsContext3D::name(t1 a1, t2 a2) \ |
{ \ |
makeContextCurrent(); gl##glname(a1,EXTRACT(a2)); \ |
} |
#define GL_SAME_METHOD_3(glname, name, t1, t2, t3) \ |
-void GRAPHICS_CONTEXT_NAME::##name(t1 a1, t2 a2, t3 a3) \ |
+void GraphicsContext3D::name(t1 a1, t2 a2, t3 a3) \ |
{ \ |
makeContextCurrent(); gl##glname(a1,a2,a3); \ |
} |
#define GL_SAME_METHOD_3_X12(glname, name, t1, t2, t3) \ |
-void GRAPHICS_CONTEXT_NAME::##name(t1 a1, t2 a2, t3 a3) \ |
+void GraphicsContext3D::name(t1 a1, t2 a2, t3 a3) \ |
{ \ |
makeContextCurrent(); gl##glname(EXTRACT(a1),EXTRACT(a2),a3); \ |
} |
#define GL_SAME_METHOD_3_X2(glname, name, t1, t2, t3) \ |
-void GRAPHICS_CONTEXT_NAME::##name(t1 a1, t2 a2, t3 a3) \ |
+void GraphicsContext3D::name(t1 a1, t2 a2, t3 a3) \ |
{ \ |
makeContextCurrent(); gl##glname(a1,EXTRACT(a2),a3); \ |
} |
#define GL_SAME_METHOD_4(glname, name, t1, t2, t3, t4) \ |
-void GRAPHICS_CONTEXT_NAME::##name(t1 a1, t2 a2, t3 a3, t4 a4) \ |
+void GraphicsContext3D::name(t1 a1, t2 a2, t3 a3, t4 a4) \ |
{ \ |
makeContextCurrent(); gl##glname(a1,a2,a3,a4); \ |
} |
#define GL_SAME_METHOD_4_X4(glname, name, t1, t2, t3, t4) \ |
-void GRAPHICS_CONTEXT_NAME::##name(t1 a1, t2 a2, t3 a3, t4 a4) \ |
+void GraphicsContext3D::name(t1 a1, t2 a2, t3 a3, t4 a4) \ |
{ \ |
makeContextCurrent(); gl##glname(a1,a2,a3,EXTRACT(a4)); \ |
} |
#define GL_SAME_METHOD_5(glname, name, t1, t2, t3, t4, t5) \ |
-void GRAPHICS_CONTEXT_NAME::##name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5) \ |
+void GraphicsContext3D::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5) \ |
{ \ |
makeContextCurrent(); gl##glname(a1,a2,a3,a4,a5); \ |
} |
#define GL_SAME_METHOD_5_X4(glname, name, t1, t2, t3, t4, t5) \ |
-void GRAPHICS_CONTEXT_NAME::##name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5) \ |
+void GraphicsContext3D::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5) \ |
{ \ |
makeContextCurrent(); gl##glname(a1,a2,a3,EXTRACT(a4),a5); \ |
} |
#define GL_SAME_METHOD_6(glname, name, t1, t2, t3, t4, t5, t6) \ |
-void GRAPHICS_CONTEXT_NAME::##name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6) \ |
+void GraphicsContext3D::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6) \ |
{ \ |
makeContextCurrent(); gl##glname(a1,a2,a3,a4,a5,a6); \ |
} |
#define GL_SAME_METHOD_8(glname, name, t1, t2, t3, t4, t5, t6, t7, t8) \ |
-void GRAPHICS_CONTEXT_NAME::##name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6, t7 a7, t8 a8) \ |
+void GraphicsContext3D::name(t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, t6 a6, t7 a7, t8 a8) \ |
{ \ |
makeContextCurrent(); gl##glname(a1,a2,a3,a4,a5,a6,a7,a8); \ |
} |
@@ -1066,10 +1050,7 @@ |
GL_SAME_METHOD_1(ClearStencil, clearStencil, long) |
-void GraphicsContext3D::colorMask(bool red, bool green, bool blue, bool alpha) |
-{ |
- m_internal->colorMask(red, green, blue, alpha); |
-} |
+GL_SAME_METHOD_4(ColorMask, colorMask, bool, bool, bool, bool) |
GL_SAME_METHOD_1_X(CompileShader, compileShader, CanvasShader*) |
@@ -1081,10 +1062,7 @@ |
GL_SAME_METHOD_1(DepthFunc, depthFunc, unsigned long) |
-void GraphicsContext3D::depthMask(bool flag) |
-{ |
- m_internal->depthMask(flag); |
-} |
+GL_SAME_METHOD_1(DepthMask, depthMask, bool) |
GL_SAME_METHOD_2(DepthRange, depthRange, double, double) |
@@ -1097,10 +1075,7 @@ |
glDetachShader(EXTRACT(program), EXTRACT(shader)); |
} |
-void GraphicsContext3D::disable(unsigned long cap) |
-{ |
- m_internal->disable(cap); |
-} |
+GL_SAME_METHOD_1(Disable, disable, unsigned long) |
void GraphicsContext3D::disableVertexAttribArray(unsigned long index) |
{ |
@@ -1156,10 +1131,7 @@ |
reinterpret_cast<void*>(static_cast<intptr_t>(offset))); |
} |
-void GraphicsContext3D::enable(unsigned long cap) |
-{ |
- m_internal->enable(cap); |
-} |
+GL_SAME_METHOD_1(Enable, enable, unsigned long) |
void GraphicsContext3D::enableVertexAttribArray(unsigned long index) |
{ |
@@ -1680,45 +1652,35 @@ |
} |
} |
-int GraphicsContext3D::texImage2D(unsigned target, unsigned level, HTMLImageElement* image, |
- bool flipY, bool premultiplyAlpha) |
+// FIXME: this must be changed to refer to the original image data |
+// rather than unmultiplying the alpha channel. |
+static int texImage2DHelper(unsigned target, unsigned level, |
+ int width, int height, |
+ int rowBytes, |
+ bool flipY, |
+ bool premultiplyAlpha, |
+ GLenum format, |
+ bool skipAlpha, |
+ unsigned char* pixels) |
{ |
- CachedImage* cachedImage = image->cachedImage(); |
- if (cachedImage == NULL) { |
- ASSERT_NOT_REACHED(); |
- return -1; |
+ ASSERT(format == GL_RGBA || format == GL_BGRA); |
+ GLint internalFormat = GL_RGBA8; |
+ if (skipAlpha) { |
+ internalFormat = GL_RGB8; |
+ // Ignore the alpha channel |
+ premultiplyAlpha = true; |
} |
- Image* img = cachedImage->image(); |
- NativeImageSkia* skiaImage = img->nativeImageForCurrentFrame(); |
- if (skiaImage == NULL) { |
- ASSERT_NOT_REACHED(); |
- return -1; |
- } |
- SkBitmap::Config skiaConfig = skiaImage->config(); |
- // FIXME: must support more image configurations. |
- if (skiaConfig != SkBitmap::kARGB_8888_Config) { |
- ASSERT_NOT_REACHED(); |
- return -1; |
- } |
- SkBitmap& skiaImageRef = *skiaImage; |
- SkAutoLockPixels lock(skiaImageRef); |
- int width = skiaImage->width(); |
- int height = skiaImage->height(); |
if (flipY) { |
// Need to flip images vertically. To avoid making a copy of |
// the entire image, we perform a ton of glTexSubImage2D |
// calls. FIXME: should rethink this strategy for efficiency. |
- glTexImage2D(target, level, GL_RGBA8, |
+ glTexImage2D(target, level, internalFormat, |
width, |
height, |
0, |
- GL_BGRA, |
+ format, |
GL_UNSIGNED_BYTE, |
NULL); |
- unsigned char* pixels = |
- reinterpret_cast<unsigned char*>(skiaImage->getPixels()); |
- int rowBytes = skiaImage->rowBytes(); |
- |
unsigned char* row = NULL; |
bool allocatedRow = false; |
if (!premultiplyAlpha) { |
@@ -1734,7 +1696,7 @@ |
} |
glTexSubImage2D(target, level, 0, height - i - 1, |
width, 1, |
- GL_BGRA, |
+ format, |
GL_UNSIGNED_BYTE, |
row); |
} |
@@ -1745,31 +1707,28 @@ |
// scanline ordering, unlike GL_TEXTURE_2D, so when uploading |
// these, the above vertical flip is the wrong thing to do. |
if (premultiplyAlpha) |
- glTexImage2D(target, level, GL_RGBA8, |
+ glTexImage2D(target, level, internalFormat, |
width, |
height, |
0, |
- GL_BGRA, |
+ format, |
GL_UNSIGNED_BYTE, |
- skiaImage->getPixels()); |
+ pixels); |
else { |
- glTexImage2D(target, level, GL_RGBA8, |
+ glTexImage2D(target, level, internalFormat, |
width, |
height, |
0, |
- GL_BGRA, |
+ format, |
GL_UNSIGNED_BYTE, |
NULL); |
- unsigned char* pixels = |
- reinterpret_cast<unsigned char*>(skiaImage->getPixels()); |
- int rowBytes = skiaImage->rowBytes(); |
unsigned char* row = new unsigned char[rowBytes]; |
for (int i = 0; i < height; i++) { |
memcpy(row, pixels + (rowBytes * i), rowBytes); |
unmultiplyAlpha(row, width); |
glTexSubImage2D(target, level, 0, i, |
width, 1, |
- GL_BGRA, |
+ format, |
GL_UNSIGNED_BYTE, |
row); |
} |
@@ -1779,6 +1738,74 @@ |
return 0; |
} |
+int GraphicsContext3D::texImage2D(unsigned target, unsigned level, HTMLImageElement* image, |
+ bool flipY, bool premultiplyAlpha) |
+{ |
+ CachedImage* cachedImage = image->cachedImage(); |
+ if (cachedImage == NULL) { |
+ ASSERT_NOT_REACHED(); |
+ return -1; |
+ } |
+ Image* img = cachedImage->image(); |
+ int res = -1; |
+#if PLATFORM(SKIA) |
+ NativeImageSkia* skiaImage = img->nativeImageForCurrentFrame(); |
+ if (skiaImage == NULL) { |
+ ASSERT_NOT_REACHED(); |
+ return -1; |
+ } |
+ SkBitmap::Config skiaConfig = skiaImage->config(); |
+ // FIXME: must support more image configurations. |
+ if (skiaConfig != SkBitmap::kARGB_8888_Config) { |
+ ASSERT_NOT_REACHED(); |
+ return -1; |
+ } |
+ SkBitmap& skiaImageRef = *skiaImage; |
+ SkAutoLockPixels lock(skiaImageRef); |
+ int width = skiaImage->width(); |
+ int height = skiaImage->height(); |
+ unsigned char* pixels = |
+ reinterpret_cast<unsigned char*>(skiaImage->getPixels()); |
+ int rowBytes = skiaImage->rowBytes(); |
+ res = texImage2DHelper(target, level, |
+ width, height, |
+ rowBytes, |
+ flipY, premultiplyAlpha, |
+ GL_BGRA, |
+ false, |
+ pixels); |
+#elif PLATFORM(CG) |
+ CGImageRef cgImage = img->nativeImageForCurrentFrame(); |
+ if (cgImage == NULL) { |
+ ASSERT_NOT_REACHED(); |
+ return -1; |
+ } |
+ int width = CGImageGetWidth(cgImage); |
+ int height = CGImageGetHeight(cgImage); |
+ int rowBytes = width * 4; |
+ CGImageAlphaInfo info = CGImageGetAlphaInfo(cgImage); |
+ bool skipAlpha = (info == kCGImageAlphaNone || |
+ info == kCGImageAlphaNoneSkipLast || |
+ info == kCGImageAlphaNoneSkipFirst); |
+ unsigned char* imageData = new unsigned char[height * rowBytes]; |
+ CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); |
+ CGContextRef tmpContext = CGBitmapContextCreate(imageData, width, height, 8, rowBytes, |
+ colorSpace, |
+ kCGImageAlphaPremultipliedLast); |
+ CGColorSpaceRelease(colorSpace); |
+ CGContextDrawImage(tmpContext, |
+ CGRectMake(0, 0, static_cast<CGFloat>(width), static_cast<CGFloat>(height)), |
+ cgImage); |
+ CGContextRelease(tmpContext); |
+ res = texImage2DHelper(target, level, width, height, rowBytes, |
+ flipY, premultiplyAlpha, GL_RGBA, skipAlpha, imageData); |
+ delete[] imageData; |
+#else |
+#error Must port to your platform |
+#endif |
+ return res; |
+} |
+ |
int GraphicsContext3D::texImage2D(unsigned target, unsigned level, HTMLCanvasElement* canvas, |
bool flipY, bool premultiplyAlpha) |
{ |
@@ -1956,10 +1983,7 @@ |
glUniformMatrix4fv(location, size, transpose, value); |
} |
-void GraphicsContext3D::useProgram(CanvasProgram* program) |
-{ |
- m_internal->useProgram(program); |
-} |
+GL_SAME_METHOD_1_X(UseProgram, useProgram, CanvasProgram*) |
GL_SAME_METHOD_1_X(ValidateProgram, validateProgram, CanvasProgram*) |