X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Fbuffers.c;h=5dc00116ead04ac020e97cee355b7cde331f7b74;hb=11929895332213363628d632f7f9f6d79b5124d1;hp=7bb5725d0857b6170e78dabe7260b9d696c07038;hpb=d3cafc18fced872ce60060e792f6faf2b97cc3a9;p=mesa.git diff --git a/src/mesa/main/buffers.c b/src/mesa/main/buffers.c index 7bb5725d085..5dc00116ead 100644 --- a/src/mesa/main/buffers.c +++ b/src/mesa/main/buffers.c @@ -35,8 +35,10 @@ #include "context.h" #include "enums.h" #include "fbobject.h" +#include "hash.h" #include "mtypes.h" #include "util/bitscan.h" +#include "util/u_math.h" #define BAD_MASK ~0u @@ -83,6 +85,48 @@ supported_buffer_bitmask(const struct gl_context *ctx, return mask; } +GLenum +_mesa_back_to_front_if_single_buffered(const struct gl_framebuffer *fb, + GLenum buffer) +{ + /* If the front buffer is the only buffer, GL_BACK and all other flags + * that include BACK select the front buffer for drawing. There are + * several reasons we want to do this. + * + * 1) OpenGL ES 3.0 requires it: + * + * Page 181 (page 192 of the PDF) in section 4.2.1 of the OpenGL + * ES 3.0.1 specification says: + * + * "When draw buffer zero is BACK, color values are written + * into the sole buffer for single-buffered contexts, or into + * the back buffer for double-buffered contexts." + * + * We also do this for GLES 1 and 2 because those APIs have no + * concept of selecting the front and back buffer anyway and it's + * convenient to be able to maintain the magic behaviour of + * GL_BACK in that case. + * + * 2) Pbuffers are back buffers from the application point of view, + * but they are front buffers from the Mesa point of view, + * because they are always single buffered. + */ + if (!fb->Visual.doubleBufferMode) { + switch (buffer) { + case GL_BACK: + buffer = GL_FRONT; + break; + case GL_BACK_RIGHT: + buffer = GL_FRONT_RIGHT; + break; + case GL_BACK_LEFT: + buffer = GL_FRONT_LEFT; + break; + } + } + + return buffer; +} /** * Helper routine used by glDrawBuffer and glDrawBuffersARB. @@ -92,32 +136,14 @@ supported_buffer_bitmask(const struct gl_context *ctx, static GLbitfield draw_buffer_enum_to_bitmask(const struct gl_context *ctx, GLenum buffer) { + buffer = _mesa_back_to_front_if_single_buffered(ctx->DrawBuffer, buffer); + switch (buffer) { case GL_NONE: return 0; case GL_FRONT: return BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_FRONT_RIGHT; case GL_BACK: - if (_mesa_is_gles(ctx)) { - /* Page 181 (page 192 of the PDF) in section 4.2.1 of the OpenGL - * ES 3.0.1 specification says: - * - * "When draw buffer zero is BACK, color values are written - * into the sole buffer for single-buffered contexts, or into - * the back buffer for double-buffered contexts." - * - * Since there is no stereo rendering in ES 3.0, only return the - * LEFT bits. This also satisfies the "n must be 1" requirement. - * - * We also do this for GLES 1 and 2 because those APIs have no - * concept of selecting the front and back buffer anyway and it's - * convenient to be able to maintain the magic behaviour of - * GL_BACK in that case. - */ - if (ctx->DrawBuffer->Visual.doubleBufferMode) - return BUFFER_BIT_BACK_LEFT; - return BUFFER_BIT_FRONT_LEFT; - } return BUFFER_BIT_BACK_LEFT | BUFFER_BIT_BACK_RIGHT; case GL_RIGHT: return BUFFER_BIT_FRONT_RIGHT | BUFFER_BIT_BACK_RIGHT; @@ -175,20 +201,12 @@ draw_buffer_enum_to_bitmask(const struct gl_context *ctx, GLenum buffer) static gl_buffer_index read_buffer_enum_to_index(const struct gl_context *ctx, GLenum buffer) { + buffer = _mesa_back_to_front_if_single_buffered(ctx->ReadBuffer, buffer); + switch (buffer) { case GL_FRONT: return BUFFER_FRONT_LEFT; case GL_BACK: - if (_mesa_is_gles(ctx)) { - /* In draw_buffer_enum_to_bitmask, when GLES contexts draw to - * GL_BACK with a single-buffered configuration, we actually end - * up drawing to the sole front buffer in our internal - * representation. For consistency, we must read from that - * front left buffer too. - */ - if (!ctx->DrawBuffer->Visual.doubleBufferMode) - return BUFFER_FRONT_LEFT; - } return BUFFER_BACK_LEFT; case GL_RIGHT: return BUFFER_FRONT_RIGHT; @@ -305,7 +323,9 @@ draw_buffer(struct gl_context *ctx, struct gl_framebuffer *fb, /* Call device driver function only if fb is the bound draw buffer */ if (fb == ctx->DrawBuffer) { if (ctx->Driver.DrawBuffer) - ctx->Driver.DrawBuffer(ctx, buffer); + ctx->Driver.DrawBuffer(ctx); + if (ctx->Driver.DrawBufferAllocate) + ctx->Driver.DrawBufferAllocate(ctx); } } @@ -358,6 +378,25 @@ _mesa_NamedFramebufferDrawBuffer_no_error(GLuint framebuffer, GLenum buf) } +void GLAPIENTRY +_mesa_FramebufferDrawBufferEXT(GLuint framebuffer, GLenum buf) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_framebuffer *fb; + + if (framebuffer) { + fb = _mesa_lookup_framebuffer_dsa(ctx, framebuffer, + "glFramebufferDrawBufferEXT"); + if (!fb) + return; + } + else + fb = ctx->WinSysDrawBuffer; + + draw_buffer_error(ctx, fb, buf, "glFramebufferDrawBufferEXT"); +} + + void GLAPIENTRY _mesa_NamedFramebufferDrawBuffer(GLuint framebuffer, GLenum buf) { @@ -434,19 +473,7 @@ draw_buffers(struct gl_context *ctx, struct gl_framebuffer *fb, GLsizei n, /* complicated error checking... */ for (output = 0; output < n; output++) { - destMask[output] = draw_buffer_enum_to_bitmask(ctx, buffers[output]); - if (!no_error) { - /* From the OpenGL 3.0 specification, page 258: - * "Each buffer listed in bufs must be one of the values from tables - * 4.5 or 4.6. Otherwise, an INVALID_ENUM error is generated. - */ - if (destMask[output] == BAD_MASK) { - _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid buffer %s)", - caller, _mesa_enum_to_string(buffers[output])); - return; - } - /* From the OpenGL 4.5 specification, page 493 (page 515 of the PDF) * "An INVALID_ENUM error is generated if any value in bufs is FRONT, * LEFT, RIGHT, or FRONT_AND_BACK . This restriction applies to both @@ -454,7 +481,7 @@ draw_buffers(struct gl_context *ctx, struct gl_framebuffer *fb, GLsizei n, * these constants may themselves refer to multiple buffers, as shown * in table 17.4." * - * And on page 492 (page 514 of the PDF): + * From the OpenGL 4.5 specification, page 492 (page 514 of the PDF): * "If the default framebuffer is affected, then each of the constants * must be one of the values listed in table 17.6 or the special value * BACK. When BACK is used, n must be 1 and color values are written @@ -466,19 +493,38 @@ draw_buffers(struct gl_context *ctx, struct gl_framebuffer *fb, GLsizei n, * For OpenGL 4.x we check that behaviour. For any previous version we * keep considering it wrong (as INVALID_ENUM). */ - if (_mesa_bitcount(destMask[output]) > 1) { - if (_mesa_is_winsys_fbo(fb) && ctx->Version >= 40 && - buffers[output] == GL_BACK) { - if (n != 1) { - _mesa_error(ctx, GL_INVALID_OPERATION, "%s(with GL_BACK n must be 1)", - caller); - return; - } - } else { - _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid buffer %s)", - caller, _mesa_enum_to_string(buffers[output])); + if (buffers[output] == GL_BACK && + _mesa_is_winsys_fbo(fb) && + _mesa_is_desktop_gl(ctx) && + ctx->Version >= 40) { + if (n != 1) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(with GL_BACK n must be 1)", + caller); return; } + } else if (buffers[output] == GL_FRONT || + buffers[output] == GL_LEFT || + buffers[output] == GL_RIGHT || + buffers[output] == GL_FRONT_AND_BACK || + (buffers[output] == GL_BACK && + _mesa_is_desktop_gl(ctx))) { + _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid buffer %s)", + caller, _mesa_enum_to_string(buffers[output])); + return; + } + } + + destMask[output] = draw_buffer_enum_to_bitmask(ctx, buffers[output]); + + if (!no_error) { + /* From the OpenGL 3.0 specification, page 258: + * "Each buffer listed in bufs must be one of the values from tables + * 4.5 or 4.6. Otherwise, an INVALID_ENUM error is generated. + */ + if (destMask[output] == BAD_MASK) { + _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid buffer %s)", + caller, _mesa_enum_to_string(buffers[output])); + return; } /* Section 4.2 (Whole Framebuffer Operations) of the OpenGL ES 3.0 @@ -586,7 +632,9 @@ draw_buffers(struct gl_context *ctx, struct gl_framebuffer *fb, GLsizei n, */ if (fb == ctx->DrawBuffer) { if (ctx->Driver.DrawBuffer) - ctx->Driver.DrawBuffer(ctx, n > 0 ? buffers[0] : GL_NONE); + ctx->Driver.DrawBuffer(ctx); + if (ctx->Driver.DrawBufferAllocate) + ctx->Driver.DrawBufferAllocate(ctx); } } @@ -622,6 +670,24 @@ _mesa_DrawBuffers(GLsizei n, const GLenum *buffers) draw_buffers_error(ctx, ctx->DrawBuffer, n, buffers, "glDrawBuffers"); } +void GLAPIENTRY +_mesa_FramebufferDrawBuffersEXT(GLuint framebuffer, GLsizei n, + const GLenum *bufs) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_framebuffer *fb; + + if (framebuffer) { + fb = _mesa_lookup_framebuffer_dsa(ctx, framebuffer, + "glFramebufferDrawBuffersEXT"); + if (!fb) + return; + } + else + fb = ctx->WinSysDrawBuffer; + + draw_buffers_error(ctx, fb, n, bufs, "glFramebufferDrawBuffersEXT"); +} void GLAPIENTRY _mesa_NamedFramebufferDrawBuffers_no_error(GLuint framebuffer, GLsizei n, @@ -718,7 +784,7 @@ _mesa_drawbuffers(struct gl_context *ctx, struct gl_framebuffer *fb, * (ex: glDrawBuffer(GL_FRONT_AND_BACK)). * Otherwise, destMask[x] can only have one bit set. */ - if (n > 0 && _mesa_bitcount(destMask[0]) > 1) { + if (n > 0 && util_bitcount(destMask[0]) > 1) { GLuint count = 0, destMask0 = destMask[0]; while (destMask0) { const gl_buffer_index bufIndex = u_bit_scan(&destMask0); @@ -737,7 +803,7 @@ _mesa_drawbuffers(struct gl_context *ctx, struct gl_framebuffer *fb, if (destMask[buf]) { gl_buffer_index bufIndex = ffs(destMask[buf]) - 1; /* only one bit should be set in the destMask[buf] field */ - assert(_mesa_bitcount(destMask[buf]) == 1); + assert(util_bitcount(destMask[buf]) == 1); if (fb->_ColorDrawBufferIndexes[buf] != bufIndex) { updated_drawbuffers(ctx, fb); fb->_ColorDrawBufferIndexes[buf] = bufIndex; @@ -932,6 +998,25 @@ _mesa_NamedFramebufferReadBuffer_no_error(GLuint framebuffer, GLenum src) } +void GLAPIENTRY +_mesa_FramebufferReadBufferEXT(GLuint framebuffer, GLenum buf) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_framebuffer *fb; + + if (framebuffer) { + fb = _mesa_lookup_framebuffer_dsa(ctx, framebuffer, + "glFramebufferReadBufferEXT"); + if (!fb) + return; + } + else + fb = ctx->WinSysDrawBuffer; + + read_buffer_err(ctx, fb, buf, "glFramebufferReadBufferEXT"); +} + + void GLAPIENTRY _mesa_NamedFramebufferReadBuffer(GLuint framebuffer, GLenum src) {