#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
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.
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;
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;
}
+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)
{
/* 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
* 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
* 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
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,
* (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);
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;
}
+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)
{