fix mesa's handling of fbo's / window fb (again)
Make sure the relevant fields in window fbs get updated at appropriate time (those are NOT the same as fbos!!!), and fix up related code accordingly. This is a bit ugly, but there's a reason the issues section in EXT_fbo is a couple hundred pages long... Hopefully correct now.
This commit is contained in:
@@ -98,9 +98,13 @@ _mesa_PushAttrib(GLbitfield mask)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mask & GL_COLOR_BUFFER_BIT) {
|
if (mask & GL_COLOR_BUFFER_BIT) {
|
||||||
|
GLuint i;
|
||||||
struct gl_colorbuffer_attrib *attr;
|
struct gl_colorbuffer_attrib *attr;
|
||||||
attr = MALLOC_STRUCT( gl_colorbuffer_attrib );
|
attr = MALLOC_STRUCT( gl_colorbuffer_attrib );
|
||||||
MEMCPY( attr, &ctx->Color, sizeof(struct gl_colorbuffer_attrib) );
|
MEMCPY( attr, &ctx->Color, sizeof(struct gl_colorbuffer_attrib) );
|
||||||
|
/* push the Draw FBO's DrawBuffer[] state, not ctx->Color.DrawBuffer[] */
|
||||||
|
for (i = 0; i < ctx->Const.MaxDrawBuffers; i ++)
|
||||||
|
attr->DrawBuffer[i] = ctx->DrawBuffer->ColorDrawBuffer[i];
|
||||||
newnode = new_attrib_node( GL_COLOR_BUFFER_BIT );
|
newnode = new_attrib_node( GL_COLOR_BUFFER_BIT );
|
||||||
newnode->data = attr;
|
newnode->data = attr;
|
||||||
newnode->next = head;
|
newnode->next = head;
|
||||||
|
@@ -370,6 +370,14 @@ _mesa_DrawBuffer(GLenum buffer)
|
|||||||
|
|
||||||
/* if we get here, there's no error so set new state */
|
/* if we get here, there's no error so set new state */
|
||||||
_mesa_drawbuffers(ctx, 1, &buffer, &destMask);
|
_mesa_drawbuffers(ctx, 1, &buffer, &destMask);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call device driver function.
|
||||||
|
*/
|
||||||
|
if (ctx->Driver.DrawBuffers)
|
||||||
|
ctx->Driver.DrawBuffers(ctx, 1, &buffer);
|
||||||
|
else if (ctx->Driver.DrawBuffer)
|
||||||
|
ctx->Driver.DrawBuffer(ctx, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -435,6 +443,14 @@ _mesa_DrawBuffersARB(GLsizei n, const GLenum *buffers)
|
|||||||
|
|
||||||
/* OK, if we get here, there were no errors so set the new state */
|
/* OK, if we get here, there were no errors so set the new state */
|
||||||
_mesa_drawbuffers(ctx, n, buffers, destMask);
|
_mesa_drawbuffers(ctx, n, buffers, destMask);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call device driver function.
|
||||||
|
*/
|
||||||
|
if (ctx->Driver.DrawBuffers)
|
||||||
|
ctx->Driver.DrawBuffers(ctx, n, buffers);
|
||||||
|
else if (ctx->Driver.DrawBuffer)
|
||||||
|
ctx->Driver.DrawBuffer(ctx, buffers[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -463,14 +479,15 @@ set_color_output(GLcontext *ctx, GLuint output, GLenum buffer,
|
|||||||
/* not really needed, will be set later */
|
/* not really needed, will be set later */
|
||||||
fb->_NumColorDrawBuffers[output] = 0;
|
fb->_NumColorDrawBuffers[output] = 0;
|
||||||
|
|
||||||
|
if (fb->Name == 0)
|
||||||
/* Set traditional state var */
|
/* Set traditional state var */
|
||||||
ctx->Color.DrawBuffer[output] = buffer;
|
ctx->Color.DrawBuffer[output] = buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper routine used by _mesa_DrawBuffer, _mesa_DrawBuffersARB and
|
* Helper routine used by _mesa_DrawBuffer, _mesa_DrawBuffersARB and
|
||||||
* _mesa_PopAttrib to set drawbuffer state.
|
* other places (window fbo fixup) to set fbo (and the old ctx) fields.
|
||||||
* All error checking will have been done prior to calling this function
|
* All error checking will have been done prior to calling this function
|
||||||
* so nothing should go wrong at this point.
|
* so nothing should go wrong at this point.
|
||||||
* \param ctx current context
|
* \param ctx current context
|
||||||
@@ -479,6 +496,7 @@ set_color_output(GLcontext *ctx, GLuint output, GLenum buffer,
|
|||||||
* \param destMask array[n] of BUFFER_* bitmasks which correspond to the
|
* \param destMask array[n] of BUFFER_* bitmasks which correspond to the
|
||||||
* colorbuffer names. (i.e. GL_FRONT_AND_BACK =>
|
* colorbuffer names. (i.e. GL_FRONT_AND_BACK =>
|
||||||
* BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_BACK_LEFT).
|
* BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_BACK_LEFT).
|
||||||
|
* \param callDriver call driver or not (bad idea sometimes this is called)
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
_mesa_drawbuffers(GLcontext *ctx, GLuint n, const GLenum *buffers,
|
_mesa_drawbuffers(GLcontext *ctx, GLuint n, const GLenum *buffers,
|
||||||
@@ -509,30 +527,15 @@ _mesa_drawbuffers(GLcontext *ctx, GLuint n, const GLenum *buffers,
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx->NewState |= _NEW_COLOR;
|
ctx->NewState |= _NEW_COLOR;
|
||||||
|
|
||||||
/*
|
|
||||||
* Call device driver function.
|
|
||||||
*/
|
|
||||||
if (ctx->Driver.DrawBuffers)
|
|
||||||
ctx->Driver.DrawBuffers(ctx, n, buffers);
|
|
||||||
else if (ctx->Driver.DrawBuffer)
|
|
||||||
ctx->Driver.DrawBuffer(ctx, buffers[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GLboolean
|
||||||
/**
|
_mesa_readbuffer_update_fields(GLcontext *ctx, GLenum buffer)
|
||||||
* Called by glReadBuffer to set the source renderbuffer for reading pixels.
|
|
||||||
* \param mode color buffer such as GL_FRONT, GL_BACK, etc.
|
|
||||||
*/
|
|
||||||
void GLAPIENTRY
|
|
||||||
_mesa_ReadBuffer(GLenum buffer)
|
|
||||||
{
|
{
|
||||||
struct gl_framebuffer *fb;
|
struct gl_framebuffer *fb;
|
||||||
GLbitfield supportedMask;
|
GLbitfield supportedMask;
|
||||||
GLint srcBuffer;
|
GLint srcBuffer;
|
||||||
GET_CURRENT_CONTEXT(ctx);
|
|
||||||
ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
|
|
||||||
|
|
||||||
fb = ctx->ReadBuffer;
|
fb = ctx->ReadBuffer;
|
||||||
|
|
||||||
@@ -548,20 +551,43 @@ _mesa_ReadBuffer(GLenum buffer)
|
|||||||
srcBuffer = read_buffer_enum_to_index(buffer);
|
srcBuffer = read_buffer_enum_to_index(buffer);
|
||||||
if (srcBuffer == -1) {
|
if (srcBuffer == -1) {
|
||||||
_mesa_error(ctx, GL_INVALID_ENUM, "glReadBuffer(buffer=0x%x)", buffer);
|
_mesa_error(ctx, GL_INVALID_ENUM, "glReadBuffer(buffer=0x%x)", buffer);
|
||||||
return;
|
return GL_FALSE;
|
||||||
}
|
}
|
||||||
supportedMask = supported_buffer_bitmask(ctx, fb);
|
supportedMask = supported_buffer_bitmask(ctx, fb);
|
||||||
if (((1 << srcBuffer) & supportedMask) == 0) {
|
if (((1 << srcBuffer) & supportedMask) == 0) {
|
||||||
_mesa_error(ctx, GL_INVALID_OPERATION, "glReadBuffer(buffer=0x%x)", buffer);
|
_mesa_error(ctx, GL_INVALID_OPERATION, "glReadBuffer(buffer=0x%x)", buffer);
|
||||||
return;
|
return GL_FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx->Pixel.ReadBuffer = buffer;
|
if (fb->Name == 0) {
|
||||||
|
ctx->Pixel.ReadBuffer = buffer;
|
||||||
|
}
|
||||||
fb->ColorReadBuffer = buffer;
|
fb->ColorReadBuffer = buffer;
|
||||||
fb->_ColorReadBufferIndex = srcBuffer;
|
fb->_ColorReadBufferIndex = srcBuffer;
|
||||||
|
|
||||||
|
return GL_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by glReadBuffer to set the source renderbuffer for reading pixels.
|
||||||
|
* \param mode color buffer such as GL_FRONT, GL_BACK, etc.
|
||||||
|
* \param callDriver call driver or not (bad idea sometimes this is called)
|
||||||
|
*/
|
||||||
|
void GLAPIENTRY
|
||||||
|
_mesa_ReadBuffer(GLenum buffer)
|
||||||
|
{
|
||||||
|
GET_CURRENT_CONTEXT(ctx);
|
||||||
|
ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
|
||||||
|
|
||||||
|
if (MESA_VERBOSE & VERBOSE_API)
|
||||||
|
_mesa_debug(ctx, "glReadBuffer %s\n", _mesa_lookup_enum_by_nr(buffer));
|
||||||
|
|
||||||
|
if (!_mesa_readbuffer_update_fields(ctx, buffer))
|
||||||
|
return;
|
||||||
|
|
||||||
ctx->NewState |= _NEW_PIXEL;
|
ctx->NewState |= _NEW_PIXEL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -56,6 +56,9 @@ extern void
|
|||||||
_mesa_drawbuffers(GLcontext *ctx, GLuint n, const GLenum *buffers,
|
_mesa_drawbuffers(GLcontext *ctx, GLuint n, const GLenum *buffers,
|
||||||
const GLbitfield *destMask);
|
const GLbitfield *destMask);
|
||||||
|
|
||||||
|
extern GLboolean
|
||||||
|
_mesa_readbuffer_update_fields(GLcontext *ctx, GLenum buffer);
|
||||||
|
|
||||||
extern void GLAPIENTRY
|
extern void GLAPIENTRY
|
||||||
_mesa_ReadBuffer( GLenum mode );
|
_mesa_ReadBuffer( GLenum mode );
|
||||||
|
|
||||||
|
@@ -1496,14 +1496,8 @@ _mesa_make_current( GLcontext *newCtx, GLframebuffer *drawBuffer,
|
|||||||
if (!newCtx->DrawBuffer || newCtx->DrawBuffer->Name == 0) {
|
if (!newCtx->DrawBuffer || newCtx->DrawBuffer->Name == 0) {
|
||||||
_mesa_reference_framebuffer(&newCtx->DrawBuffer, drawBuffer);
|
_mesa_reference_framebuffer(&newCtx->DrawBuffer, drawBuffer);
|
||||||
/* fix up the fb fields - these will end up wrong otherwise
|
/* fix up the fb fields - these will end up wrong otherwise
|
||||||
if the DRIdrawable changes, and someone may rely on them.
|
if the DRIdrawable changes, and everything relies on them.
|
||||||
*/
|
This is a bit messy (same as needed in _mesa_BindFramebufferEXT) */
|
||||||
/* What a mess!?! */
|
|
||||||
/* XXX this is still not quite correct. Imagine a user-created fbo
|
|
||||||
bound on a context. Now rebind with a completely new drawable.
|
|
||||||
Upon rebinding to the window-framebuffer, we have no idea what
|
|
||||||
the read and write buffers should be (front, back, ...) - that
|
|
||||||
information was only available in the previously used drawable... */
|
|
||||||
int i;
|
int i;
|
||||||
GLenum buffers[MAX_DRAW_BUFFERS];
|
GLenum buffers[MAX_DRAW_BUFFERS];
|
||||||
for(i = 0; i < newCtx->Const.MaxDrawBuffers; i++) {
|
for(i = 0; i < newCtx->Const.MaxDrawBuffers; i++) {
|
||||||
@@ -1513,7 +1507,7 @@ _mesa_make_current( GLcontext *newCtx, GLframebuffer *drawBuffer,
|
|||||||
}
|
}
|
||||||
if (!newCtx->ReadBuffer || newCtx->ReadBuffer->Name == 0) {
|
if (!newCtx->ReadBuffer || newCtx->ReadBuffer->Name == 0) {
|
||||||
_mesa_reference_framebuffer(&newCtx->ReadBuffer, readBuffer);
|
_mesa_reference_framebuffer(&newCtx->ReadBuffer, readBuffer);
|
||||||
_mesa_ReadBuffer(newCtx->Pixel.ReadBuffer);
|
_mesa_readbuffer_update_fields(newCtx, newCtx->Pixel.ReadBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
newCtx->NewState |= _NEW_BUFFERS;
|
newCtx->NewState |= _NEW_BUFFERS;
|
||||||
|
@@ -29,6 +29,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "buffers.h"
|
||||||
#include "context.h"
|
#include "context.h"
|
||||||
#include "fbobject.h"
|
#include "fbobject.h"
|
||||||
#include "framebuffer.h"
|
#include "framebuffer.h"
|
||||||
@@ -1001,23 +1002,32 @@ _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
|
|||||||
* XXX check if re-binding same buffer and skip some of this code.
|
* XXX check if re-binding same buffer and skip some of this code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* for window-framebuffers, re-initialize the fbo values, as they
|
||||||
|
could be wrong (makecurrent with a new drawable while still a fbo
|
||||||
|
was bound will lead to default init fbo values).
|
||||||
|
note that therefore the context ReadBuffer/DrawBuffer values are not
|
||||||
|
valid while fbo's are bound!!! */
|
||||||
if (bindReadBuf) {
|
if (bindReadBuf) {
|
||||||
_mesa_reference_framebuffer(&ctx->ReadBuffer, newFbread);
|
_mesa_reference_framebuffer(&ctx->ReadBuffer, newFbread);
|
||||||
/* set context value */
|
if (!newFbread->Name) {
|
||||||
ctx->Pixel.ReadBuffer = newFbread->ColorReadBuffer;
|
_mesa_readbuffer_update_fields(ctx, ctx->Pixel.ReadBuffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bindDrawBuf) {
|
if (bindDrawBuf) {
|
||||||
GLuint i;
|
|
||||||
/* check if old FB had any texture attachments */
|
/* check if old FB had any texture attachments */
|
||||||
check_end_texture_render(ctx, ctx->DrawBuffer);
|
check_end_texture_render(ctx, ctx->DrawBuffer);
|
||||||
/* check if time to delete this framebuffer */
|
/* check if time to delete this framebuffer */
|
||||||
_mesa_reference_framebuffer(&ctx->DrawBuffer, newFb);
|
_mesa_reference_framebuffer(&ctx->DrawBuffer, newFb);
|
||||||
/* set context value */
|
if (!newFb->Name) {
|
||||||
for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) {
|
GLuint i;
|
||||||
ctx->Color.DrawBuffer[i] = newFb->ColorDrawBuffer[i];
|
GLenum buffers[MAX_DRAW_BUFFERS];
|
||||||
|
for(i = 0; i < ctx->Const.MaxDrawBuffers; i++) {
|
||||||
|
buffers[i] = ctx->Color.DrawBuffer[i];
|
||||||
|
}
|
||||||
|
_mesa_drawbuffers(ctx, ctx->Const.MaxDrawBuffers, buffers, NULL);
|
||||||
}
|
}
|
||||||
if (newFb->Name != 0) {
|
else {
|
||||||
/* check if newly bound framebuffer has any texture attachments */
|
/* check if newly bound framebuffer has any texture attachments */
|
||||||
check_begin_texture_render(ctx, newFb);
|
check_begin_texture_render(ctx, newFb);
|
||||||
}
|
}
|
||||||
|
@@ -695,8 +695,7 @@ _mesa_update_framebuffer(GLcontext *ctx)
|
|||||||
struct gl_framebuffer *fbread = ctx->ReadBuffer;
|
struct gl_framebuffer *fbread = ctx->ReadBuffer;
|
||||||
|
|
||||||
update_framebuffer(ctx, fb);
|
update_framebuffer(ctx, fb);
|
||||||
if (fbread != fb && fbread != NULL /* can happen at make_current -
|
if (fbread != fb)
|
||||||
core/driver circular dependencies, should be fixed up */)
|
|
||||||
update_framebuffer(ctx, fbread);
|
update_framebuffer(ctx, fbread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user