[Mesa-dev] [PATCH 6/6] mesa: Fix framebuffer blitting to GL_COLOR_ATTACHMENTi when i!=0
Kenneth Graunke
kenneth at whitecape.org
Tue Dec 18 11:57:59 PST 2012
On 12/17/2012 07:35 PM, Anuj Phogat wrote:
> This patch fixes a case when blitting to a framebuffer with
> renderbuffers/textures attached to GL_COLOR_ATTACHMENT{1, 2, ...}.
> Earlier we were incorrectly blitting to GL_COLOR_ATTACHMENT0 by default.
>
> It also fixes a blitting case when drawAttachment->Texture ==
> readAttachment->Texture. This was causing an assertion failure in intel's
> i965 drivers (intel_miptree_attach_map()) with gles3 conformance test case:
> framebuffer_blit_functionality_minifying_blit
>
> V2: Fixed a case when number of draw buffer attachments are zero.
> Signed-off-by: Anuj Phogat <anuj.phogat at gmail.com>
> ---
> src/mesa/main/fbobject.c | 14 +++++++++++++-
> src/mesa/swrast/s_blit.c | 33 ++++++++++++++++++++++++++-------
> 2 files changed, 39 insertions(+), 8 deletions(-)
>
> diff --git a/src/mesa/main/fbobject.c b/src/mesa/main/fbobject.c
> index d87239e..f4e427b 100644
> --- a/src/mesa/main/fbobject.c
> +++ b/src/mesa/main/fbobject.c
> @@ -2818,8 +2818,20 @@ _mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
>
> /* get color read/draw renderbuffers */
> if (mask & GL_COLOR_BUFFER_BIT) {
> + const GLuint numColorDrawBuffers =
> + ctx->DrawBuffer->_NumColorDrawBuffers;
> colorReadRb = readFb->_ColorReadBuffer;
> - colorDrawRb = drawFb->_ColorDrawBuffers[0];
> +
> + if (numColorDrawBuffers > 0) {
> + for (int i = 0; i < numColorDrawBuffers; i++) {
> + if (ctx->DrawBuffer->_ColorDrawBuffers[i] != NULL) {
> + colorDrawRb = ctx->DrawBuffer->_ColorDrawBuffers[i];
> + break;
> + }
> + }
> + }
> + else
> + colorDrawRb = NULL;
This looks wrong to me. You're looping through all the draw buffers,
advancing the pointer until you find the first drawbuffer, then
stopping...but you're not doing any checks.
I believe you actually want to check the read buffer against *each* of
the draw buffers, i.e.
colorReadRb = readFb->_ColorReadBuffer;
for (int i = 0; i < numColorDrawBuffers; i++) {
if (ctx->DrawBuffer->_ColorDrawBuffers[i] == NULL) {
continue;
/* From the EXT_framebuffer_object spec: ... */
if (colorReadRb == NULL || colorDrawRb == NULL) {
colorReadRb = colorDrawRb = NULL;
mask &= ~GL_COLOR_BUFFER_BIT;
break;
} else if (!compatible_color_datatypes(...)) {
...error...
return;
}
}
}
It looks like the compatible_resolve_formats check (below) should also
be in this loop, so it happens on a per-buffer basis.
I believe my interpretation of checking the read buffer against *all*
color draw buffers is correct. For example, this spec text:
"The read buffer contains signed integer values and **any** draw buffer
does not contain signed integer values."
...really seems to imply that we should be applying these error checks
to each of the draw buffers in turn.
>
> /* From the EXT_framebuffer_object spec:
> *
> diff --git a/src/mesa/swrast/s_blit.c b/src/mesa/swrast/s_blit.c
> index b0c56a4..c579572 100644
> --- a/src/mesa/swrast/s_blit.c
> +++ b/src/mesa/swrast/s_blit.c
> @@ -111,6 +111,9 @@ blit_nearest(struct gl_context *ctx,
> GLbitfield buffer)
> {
> struct gl_renderbuffer *readRb, *drawRb;
> + struct gl_renderbuffer_attachment *readAtt, *drawAtt;
> + struct gl_framebuffer *readFb = ctx->ReadBuffer;
> + struct gl_framebuffer *drawFb = ctx->DrawBuffer;
>
> const GLint srcWidth = ABS(srcX1 - srcX0);
> const GLint dstWidth = ABS(dstX1 - dstX0);
> @@ -146,8 +149,18 @@ blit_nearest(struct gl_context *ctx,
>
> switch (buffer) {
> case GL_COLOR_BUFFER_BIT:
> - readRb = ctx->ReadBuffer->_ColorReadBuffer;
> - drawRb = ctx->DrawBuffer->_ColorDrawBuffers[0];
> + readAtt = &readFb->Attachment[readFb->_ColorReadBufferIndex];
> + for (int i = 0; i < drawFb->_NumColorDrawBuffers; i++) {
> + int idx = drawFb->_ColorDrawBufferIndexes[i];
> + if (idx != -1) {
> + drawAtt = &drawFb->Attachment[idx];
> + }
> + else {
> + continue;
if (idx == -1)
continue;
drawAtt = &drawFb->Attachment[idx];
but again, I'm skeptical here since this loop finds the last draw
attachment and doesn't do anything with the prior ones...
> + }
> + }
> + readRb = readFb->_ColorReadBuffer;
> + drawRb = drawAtt->Renderbuffer;
>
> if (readRb->Format == drawRb->Format) {
> mode = DIRECT;
> @@ -159,8 +172,10 @@ blit_nearest(struct gl_context *ctx,
>
> break;
> case GL_DEPTH_BUFFER_BIT:
> - readRb = ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
> - drawRb = ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
> + readAtt = &readFb->Attachment[BUFFER_DEPTH];
> + drawAtt = &drawFb->Attachment[BUFFER_DEPTH];
> + readRb = readAtt->Renderbuffer;
> + drawRb = drawAtt->Renderbuffer;
>
> /* Note that for depth/stencil, the formats of src/dst must match. By
> * using the core helpers for pack/unpack, we avoid needing to handle
> @@ -175,8 +190,10 @@ blit_nearest(struct gl_context *ctx,
> pixelSize = 4;
> break;
> case GL_STENCIL_BUFFER_BIT:
> - readRb = ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
> - drawRb = ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
> + readAtt = &readFb->Attachment[BUFFER_STENCIL];
> + drawAtt = &drawFb->Attachment[BUFFER_STENCIL];
> + readRb = readAtt->Renderbuffer;
> + drawRb = drawAtt->Renderbuffer;
> mode = UNPACK_S;
> pixelSize = 1;
> break;
> @@ -208,7 +225,9 @@ blit_nearest(struct gl_context *ctx,
> return;
> }
>
> - if (readRb == drawRb) {
> + if ((readRb == drawRb) ||
> + (readAtt->Texture && drawAtt->Texture &&
> + (readAtt->Texture == drawAtt->Texture))) {
> /* map whole buffer for read/write */
> /* XXX we could be clever and just map the union region of the
> * source and dest rects.
>
More information about the mesa-dev
mailing list