mesa: move glBlitFramebuffer code into new blit.c file

Just for better organization.
v2: update gl_genexec.py too (not api_exec.c)

Acked-by: Kenneth Graunke <kenneth@whitecape.org>
This commit is contained in:
Brian Paul
2014-02-01 08:58:43 -07:00
parent 20fedfd80a
commit bfcb9bb204
7 changed files with 555 additions and 478 deletions

View File

@@ -51,6 +51,7 @@ header = """/**
#include "main/atifragshader.h" #include "main/atifragshader.h"
#include "main/attrib.h" #include "main/attrib.h"
#include "main/blend.h" #include "main/blend.h"
#include "main/blit.h"
#include "main/bufferobj.h" #include "main/bufferobj.h"
#include "main/arrayobj.h" #include "main/arrayobj.h"
#include "main/buffers.h" #include "main/buffers.h"

View File

@@ -18,6 +18,7 @@ MAIN_FILES = \
$(SRCDIR)main/attrib.c \ $(SRCDIR)main/attrib.c \
$(SRCDIR)main/arrayobj.c \ $(SRCDIR)main/arrayobj.c \
$(SRCDIR)main/blend.c \ $(SRCDIR)main/blend.c \
$(SRCDIR)main/blit.c \
$(SRCDIR)main/bufferobj.c \ $(SRCDIR)main/bufferobj.c \
$(SRCDIR)main/buffers.c \ $(SRCDIR)main/buffers.c \
$(SRCDIR)main/clear.c \ $(SRCDIR)main/clear.c \

View File

@@ -46,6 +46,7 @@ main_sources = [
'main/attrib.c', 'main/attrib.c',
'main/arrayobj.c', 'main/arrayobj.c',
'main/blend.c', 'main/blend.c',
'main/blit.c',
'main/bufferobj.c', 'main/bufferobj.c',
'main/buffers.c', 'main/buffers.c',
'main/clear.c', 'main/clear.c',

513
src/mesa/main/blit.c Normal file
View File

@@ -0,0 +1,513 @@
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
* Copyright (C) 1999-2013 VMware, Inc. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* glBlitFramebuffer functions.
*/
#include <stdbool.h>
#include "context.h"
#include "enums.h"
#include "blit.h"
#include "fbobject.h"
#include "glformats.h"
#include "mtypes.h"
#include "state.h"
/** Set this to 1 to debug/log glBlitFramebuffer() calls */
#define DEBUG_BLIT 0
static const struct gl_renderbuffer_attachment *
find_attachment(const struct gl_framebuffer *fb,
const struct gl_renderbuffer *rb)
{
GLuint i;
for (i = 0; i < Elements(fb->Attachment); i++) {
if (fb->Attachment[i].Renderbuffer == rb)
return &fb->Attachment[i];
}
return NULL;
}
/**
* Helper function for checking if the datatypes of color buffers are
* compatible for glBlitFramebuffer. From the 3.1 spec, page 198:
*
* "GL_INVALID_OPERATION is generated if mask contains GL_COLOR_BUFFER_BIT
* and any of the following conditions hold:
* - The read buffer contains fixed-point or floating-point values and any
* draw buffer contains neither fixed-point nor floating-point values.
* - The read buffer contains unsigned integer values and any draw buffer
* does not contain unsigned integer values.
* - The read buffer contains signed integer values and any draw buffer
* does not contain signed integer values."
*/
static GLboolean
compatible_color_datatypes(mesa_format srcFormat, mesa_format dstFormat)
{
GLenum srcType = _mesa_get_format_datatype(srcFormat);
GLenum dstType = _mesa_get_format_datatype(dstFormat);
if (srcType != GL_INT && srcType != GL_UNSIGNED_INT) {
assert(srcType == GL_UNSIGNED_NORMALIZED ||
srcType == GL_SIGNED_NORMALIZED ||
srcType == GL_FLOAT);
/* Boil any of those types down to GL_FLOAT */
srcType = GL_FLOAT;
}
if (dstType != GL_INT && dstType != GL_UNSIGNED_INT) {
assert(dstType == GL_UNSIGNED_NORMALIZED ||
dstType == GL_SIGNED_NORMALIZED ||
dstType == GL_FLOAT);
/* Boil any of those types down to GL_FLOAT */
dstType = GL_FLOAT;
}
return srcType == dstType;
}
static GLboolean
compatible_resolve_formats(const struct gl_renderbuffer *readRb,
const struct gl_renderbuffer *drawRb)
{
GLenum readFormat, drawFormat;
/* The simple case where we know the backing Mesa formats are the same.
*/
if (_mesa_get_srgb_format_linear(readRb->Format) ==
_mesa_get_srgb_format_linear(drawRb->Format)) {
return GL_TRUE;
}
/* The Mesa formats are different, so we must check whether the internal
* formats are compatible.
*
* Under some circumstances, the user may request e.g. two GL_RGBA8
* textures and get two entirely different Mesa formats like RGBA8888 and
* ARGB8888. Drivers behaving like that should be able to cope with
* non-matching formats by themselves, because it's not the user's fault.
*
* Blits between linear and sRGB formats are also allowed.
*/
readFormat = _mesa_get_nongeneric_internalformat(readRb->InternalFormat);
drawFormat = _mesa_get_nongeneric_internalformat(drawRb->InternalFormat);
readFormat = _mesa_get_linear_internalformat(readFormat);
drawFormat = _mesa_get_linear_internalformat(drawFormat);
if (readFormat == drawFormat) {
return GL_TRUE;
}
return GL_FALSE;
}
static GLboolean
is_valid_blit_filter(const struct gl_context *ctx, GLenum filter)
{
switch (filter) {
case GL_NEAREST:
case GL_LINEAR:
return true;
case GL_SCALED_RESOLVE_FASTEST_EXT:
case GL_SCALED_RESOLVE_NICEST_EXT:
return ctx->Extensions.EXT_framebuffer_multisample_blit_scaled;
default:
return false;
}
}
/**
* Blit rectangular region, optionally from one framebuffer to another.
*
* Note, if the src buffer is multisampled and the dest is not, this is
* when the samples must be resolved to a single color.
*/
void GLAPIENTRY
_mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter)
{
const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT |
GL_DEPTH_BUFFER_BIT |
GL_STENCIL_BUFFER_BIT);
const struct gl_framebuffer *readFb, *drawFb;
GET_CURRENT_CONTEXT(ctx);
FLUSH_VERTICES(ctx, 0);
if (MESA_VERBOSE & VERBOSE_API)
_mesa_debug(ctx,
"glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d, 0x%x, %s)\n",
srcX0, srcY0, srcX1, srcY1,
dstX0, dstY0, dstX1, dstY1,
mask, _mesa_lookup_enum_by_nr(filter));
if (ctx->NewState) {
_mesa_update_state(ctx);
}
readFb = ctx->ReadBuffer;
drawFb = ctx->DrawBuffer;
if (!readFb || !drawFb) {
/* This will normally never happen but someday we may want to
* support MakeCurrent() with no drawables.
*/
return;
}
/* check for complete framebuffers */
if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
_mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
"glBlitFramebufferEXT(incomplete draw/read buffers)");
return;
}
if (!is_valid_blit_filter(ctx, filter)) {
_mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(%s)",
_mesa_lookup_enum_by_nr(filter));
return;
}
if ((filter == GL_SCALED_RESOLVE_FASTEST_EXT ||
filter == GL_SCALED_RESOLVE_NICEST_EXT) &&
(readFb->Visual.samples == 0 || drawFb->Visual.samples > 0)) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT(%s)",
_mesa_lookup_enum_by_nr(filter));
return;
}
if (mask & ~legalMaskBits) {
_mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
return;
}
/* depth/stencil must be blitted with nearest filtering */
if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
&& filter != GL_NEAREST) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter)");
return;
}
/* get color read/draw renderbuffers */
if (mask & GL_COLOR_BUFFER_BIT) {
const GLuint numColorDrawBuffers = ctx->DrawBuffer->_NumColorDrawBuffers;
const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer;
const struct gl_renderbuffer *colorDrawRb = NULL;
GLuint i;
/* From the EXT_framebuffer_object spec:
*
* "If a buffer is specified in <mask> and does not exist in both
* the read and draw framebuffers, the corresponding bit is silently
* ignored."
*/
if (!colorReadRb || numColorDrawBuffers == 0) {
mask &= ~GL_COLOR_BUFFER_BIT;
}
else {
for (i = 0; i < numColorDrawBuffers; i++) {
colorDrawRb = ctx->DrawBuffer->_ColorDrawBuffers[i];
if (!colorDrawRb)
continue;
/* Page 193 (page 205 of the PDF) in section 4.3.2 of the OpenGL
* ES 3.0.1 spec says:
*
* "If the source and destination buffers are identical, an
* INVALID_OPERATION error is generated. Different mipmap
* levels of a texture, different layers of a three-
* dimensional texture or two-dimensional array texture, and
* different faces of a cube map texture do not constitute
* identical buffers."
*/
if (_mesa_is_gles3(ctx) && (colorDrawRb == colorReadRb)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBlitFramebuffer(source and destination color "
"buffer cannot be the same)");
return;
}
if (!compatible_color_datatypes(colorReadRb->Format,
colorDrawRb->Format)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBlitFramebufferEXT(color buffer datatypes mismatch)");
return;
}
/* extra checks for multisample copies... */
if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) {
/* color formats must match */
if (!compatible_resolve_formats(colorReadRb, colorDrawRb)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBlitFramebufferEXT(bad src/dst multisample pixel formats)");
return;
}
}
}
if (filter != GL_NEAREST) {
/* From EXT_framebuffer_multisample_blit_scaled specification:
* "Calling BlitFramebuffer will result in an INVALID_OPERATION error
* if filter is not NEAREST and read buffer contains integer data."
*/
GLenum type = _mesa_get_format_datatype(colorReadRb->Format);
if (type == GL_INT || type == GL_UNSIGNED_INT) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBlitFramebufferEXT(integer color type)");
return;
}
}
}
}
if (mask & GL_STENCIL_BUFFER_BIT) {
struct gl_renderbuffer *readRb =
readFb->Attachment[BUFFER_STENCIL].Renderbuffer;
struct gl_renderbuffer *drawRb =
drawFb->Attachment[BUFFER_STENCIL].Renderbuffer;
/* From the EXT_framebuffer_object spec:
*
* "If a buffer is specified in <mask> and does not exist in both
* the read and draw framebuffers, the corresponding bit is silently
* ignored."
*/
if ((readRb == NULL) || (drawRb == NULL)) {
mask &= ~GL_STENCIL_BUFFER_BIT;
}
else {
int read_z_bits, draw_z_bits;
if (_mesa_is_gles3(ctx) && (drawRb == readRb)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBlitFramebuffer(source and destination stencil "
"buffer cannot be the same)");
return;
}
if (_mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) !=
_mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) {
/* There is no need to check the stencil datatype here, because
* there is only one: GL_UNSIGNED_INT.
*/
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBlitFramebuffer(stencil attachment format mismatch)");
return;
}
read_z_bits = _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS);
draw_z_bits = _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS);
/* If both buffers also have depth data, the depth formats must match
* as well. If one doesn't have depth, it's not blitted, so we should
* ignore the depth format check.
*/
if (read_z_bits > 0 && draw_z_bits > 0 &&
(read_z_bits != draw_z_bits ||
_mesa_get_format_datatype(readRb->Format) !=
_mesa_get_format_datatype(drawRb->Format))) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebuffer"
"(stencil attachment depth format mismatch)");
return;
}
}
}
if (mask & GL_DEPTH_BUFFER_BIT) {
struct gl_renderbuffer *readRb =
readFb->Attachment[BUFFER_DEPTH].Renderbuffer;
struct gl_renderbuffer *drawRb =
drawFb->Attachment[BUFFER_DEPTH].Renderbuffer;
/* From the EXT_framebuffer_object spec:
*
* "If a buffer is specified in <mask> and does not exist in both
* the read and draw framebuffers, the corresponding bit is silently
* ignored."
*/
if ((readRb == NULL) || (drawRb == NULL)) {
mask &= ~GL_DEPTH_BUFFER_BIT;
}
else {
int read_s_bit, draw_s_bit;
if (_mesa_is_gles3(ctx) && (drawRb == readRb)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBlitFramebuffer(source and destination depth "
"buffer cannot be the same)");
return;
}
if ((_mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) !=
_mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) ||
(_mesa_get_format_datatype(readRb->Format) !=
_mesa_get_format_datatype(drawRb->Format))) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBlitFramebuffer(depth attachment format mismatch)");
return;
}
read_s_bit = _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS);
draw_s_bit = _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS);
/* If both buffers also have stencil data, the stencil formats must
* match as well. If one doesn't have stencil, it's not blitted, so
* we should ignore the stencil format check.
*/
if (read_s_bit > 0 && draw_s_bit > 0 && read_s_bit != draw_s_bit) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebuffer"
"(depth attachment stencil bits mismatch)");
return;
}
}
}
if (_mesa_is_gles3(ctx)) {
/* Page 194 (page 206 of the PDF) in section 4.3.2 of the OpenGL ES
* 3.0.1 spec says:
*
* "If SAMPLE_BUFFERS for the draw framebuffer is greater than zero,
* an INVALID_OPERATION error is generated."
*/
if (drawFb->Visual.samples > 0) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBlitFramebuffer(destination samples must be 0)");
return;
}
/* Page 194 (page 206 of the PDF) in section 4.3.2 of the OpenGL ES
* 3.0.1 spec says:
*
* "If SAMPLE_BUFFERS for the read framebuffer is greater than zero,
* no copy is performed and an INVALID_OPERATION error is generated
* if the formats of the read and draw framebuffers are not
* identical or if the source and destination rectangles are not
* defined with the same (X0, Y0) and (X1, Y1) bounds."
*
* The format check was made above because desktop OpenGL has the same
* requirement.
*/
if (readFb->Visual.samples > 0
&& (srcX0 != dstX0 || srcY0 != dstY0
|| srcX1 != dstX1 || srcY1 != dstY1)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBlitFramebuffer(bad src/dst multisample region)");
return;
}
} else {
if (readFb->Visual.samples > 0 &&
drawFb->Visual.samples > 0 &&
readFb->Visual.samples != drawFb->Visual.samples) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBlitFramebufferEXT(mismatched samples)");
return;
}
/* extra checks for multisample copies... */
if ((readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) &&
(filter == GL_NEAREST || filter == GL_LINEAR)) {
/* src and dest region sizes must be the same */
if (abs(srcX1 - srcX0) != abs(dstX1 - dstX0) ||
abs(srcY1 - srcY0) != abs(dstY1 - dstY0)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBlitFramebufferEXT(bad src/dst multisample region sizes)");
return;
}
}
}
/* Debug code */
if (DEBUG_BLIT) {
const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer;
const struct gl_renderbuffer *colorDrawRb = NULL;
GLuint i = 0;
printf("glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d,"
" 0x%x, 0x%x)\n",
srcX0, srcY0, srcX1, srcY1,
dstX0, dstY0, dstX1, dstY1,
mask, filter);
if (colorReadRb) {
const struct gl_renderbuffer_attachment *att;
att = find_attachment(readFb, colorReadRb);
printf(" Src FBO %u RB %u (%dx%d) ",
readFb->Name, colorReadRb->Name,
colorReadRb->Width, colorReadRb->Height);
if (att && att->Texture) {
printf("Tex %u tgt 0x%x level %u face %u",
att->Texture->Name,
att->Texture->Target,
att->TextureLevel,
att->CubeMapFace);
}
printf("\n");
/* Print all active color render buffers */
for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) {
colorDrawRb = ctx->DrawBuffer->_ColorDrawBuffers[i];
if (!colorDrawRb)
continue;
att = find_attachment(drawFb, colorDrawRb);
printf(" Dst FBO %u RB %u (%dx%d) ",
drawFb->Name, colorDrawRb->Name,
colorDrawRb->Width, colorDrawRb->Height);
if (att && att->Texture) {
printf("Tex %u tgt 0x%x level %u face %u",
att->Texture->Name,
att->Texture->Target,
att->TextureLevel,
att->CubeMapFace);
}
printf("\n");
}
}
}
if (!mask ||
(srcX1 - srcX0) == 0 || (srcY1 - srcY0) == 0 ||
(dstX1 - dstX0) == 0 || (dstY1 - dstY0) == 0) {
return;
}
ASSERT(ctx->Driver.BlitFramebuffer);
ctx->Driver.BlitFramebuffer(ctx,
srcX0, srcY0, srcX1, srcY1,
dstX0, dstY0, dstX1, dstY1,
mask, filter);
}

39
src/mesa/main/blit.h Normal file
View File

@@ -0,0 +1,39 @@
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef BLIT_H
#define BLIT_H
#include "compiler.h"
#include "glheader.h"
extern void GLAPIENTRY
_mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter);
#endif /* BLIT_H */

View File

@@ -50,10 +50,6 @@
#include "texobj.h" #include "texobj.h"
/** Set this to 1 to debug/log glBlitFramebuffer() calls */
#define DEBUG_BLIT 0
/** /**
* Notes: * Notes:
* *
@@ -3069,475 +3065,6 @@ _mesa_GenerateMipmap(GLenum target)
_mesa_unlock_texture(ctx, texObj); _mesa_unlock_texture(ctx, texObj);
} }
static const struct gl_renderbuffer_attachment *
find_attachment(const struct gl_framebuffer *fb,
const struct gl_renderbuffer *rb)
{
GLuint i;
for (i = 0; i < Elements(fb->Attachment); i++) {
if (fb->Attachment[i].Renderbuffer == rb)
return &fb->Attachment[i];
}
return NULL;
}
/**
* Helper function for checking if the datatypes of color buffers are
* compatible for glBlitFramebuffer. From the 3.1 spec, page 198:
*
* "GL_INVALID_OPERATION is generated if mask contains GL_COLOR_BUFFER_BIT
* and any of the following conditions hold:
* - The read buffer contains fixed-point or floating-point values and any
* draw buffer contains neither fixed-point nor floating-point values.
* - The read buffer contains unsigned integer values and any draw buffer
* does not contain unsigned integer values.
* - The read buffer contains signed integer values and any draw buffer
* does not contain signed integer values."
*/
static GLboolean
compatible_color_datatypes(mesa_format srcFormat, mesa_format dstFormat)
{
GLenum srcType = _mesa_get_format_datatype(srcFormat);
GLenum dstType = _mesa_get_format_datatype(dstFormat);
if (srcType != GL_INT && srcType != GL_UNSIGNED_INT) {
assert(srcType == GL_UNSIGNED_NORMALIZED ||
srcType == GL_SIGNED_NORMALIZED ||
srcType == GL_FLOAT);
/* Boil any of those types down to GL_FLOAT */
srcType = GL_FLOAT;
}
if (dstType != GL_INT && dstType != GL_UNSIGNED_INT) {
assert(dstType == GL_UNSIGNED_NORMALIZED ||
dstType == GL_SIGNED_NORMALIZED ||
dstType == GL_FLOAT);
/* Boil any of those types down to GL_FLOAT */
dstType = GL_FLOAT;
}
return srcType == dstType;
}
static GLboolean
compatible_resolve_formats(const struct gl_renderbuffer *readRb,
const struct gl_renderbuffer *drawRb)
{
GLenum readFormat, drawFormat;
/* The simple case where we know the backing Mesa formats are the same.
*/
if (_mesa_get_srgb_format_linear(readRb->Format) ==
_mesa_get_srgb_format_linear(drawRb->Format)) {
return GL_TRUE;
}
/* The Mesa formats are different, so we must check whether the internal
* formats are compatible.
*
* Under some circumstances, the user may request e.g. two GL_RGBA8
* textures and get two entirely different Mesa formats like RGBA8888 and
* ARGB8888. Drivers behaving like that should be able to cope with
* non-matching formats by themselves, because it's not the user's fault.
*
* Blits between linear and sRGB formats are also allowed.
*/
readFormat = _mesa_get_nongeneric_internalformat(readRb->InternalFormat);
drawFormat = _mesa_get_nongeneric_internalformat(drawRb->InternalFormat);
readFormat = _mesa_get_linear_internalformat(readFormat);
drawFormat = _mesa_get_linear_internalformat(drawFormat);
if (readFormat == drawFormat) {
return GL_TRUE;
}
return GL_FALSE;
}
static GLboolean
is_valid_blit_filter(const struct gl_context *ctx, GLenum filter)
{
switch (filter) {
case GL_NEAREST:
case GL_LINEAR:
return true;
case GL_SCALED_RESOLVE_FASTEST_EXT:
case GL_SCALED_RESOLVE_NICEST_EXT:
return ctx->Extensions.EXT_framebuffer_multisample_blit_scaled;
default:
return false;
}
}
/**
* Blit rectangular region, optionally from one framebuffer to another.
*
* Note, if the src buffer is multisampled and the dest is not, this is
* when the samples must be resolved to a single color.
*/
void GLAPIENTRY
_mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter)
{
const GLbitfield legalMaskBits = (GL_COLOR_BUFFER_BIT |
GL_DEPTH_BUFFER_BIT |
GL_STENCIL_BUFFER_BIT);
const struct gl_framebuffer *readFb, *drawFb;
GET_CURRENT_CONTEXT(ctx);
FLUSH_VERTICES(ctx, 0);
if (MESA_VERBOSE & VERBOSE_API)
_mesa_debug(ctx,
"glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d, 0x%x, %s)\n",
srcX0, srcY0, srcX1, srcY1,
dstX0, dstY0, dstX1, dstY1,
mask, _mesa_lookup_enum_by_nr(filter));
if (ctx->NewState) {
_mesa_update_state(ctx);
}
readFb = ctx->ReadBuffer;
drawFb = ctx->DrawBuffer;
if (!readFb || !drawFb) {
/* This will normally never happen but someday we may want to
* support MakeCurrent() with no drawables.
*/
return;
}
/* check for complete framebuffers */
if (drawFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT ||
readFb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) {
_mesa_error(ctx, GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
"glBlitFramebufferEXT(incomplete draw/read buffers)");
return;
}
if (!is_valid_blit_filter(ctx, filter)) {
_mesa_error(ctx, GL_INVALID_ENUM, "glBlitFramebufferEXT(%s)",
_mesa_lookup_enum_by_nr(filter));
return;
}
if ((filter == GL_SCALED_RESOLVE_FASTEST_EXT ||
filter == GL_SCALED_RESOLVE_NICEST_EXT) &&
(readFb->Visual.samples == 0 || drawFb->Visual.samples > 0)) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebufferEXT(%s)",
_mesa_lookup_enum_by_nr(filter));
return;
}
if (mask & ~legalMaskBits) {
_mesa_error( ctx, GL_INVALID_VALUE, "glBlitFramebufferEXT(mask)");
return;
}
/* depth/stencil must be blitted with nearest filtering */
if ((mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
&& filter != GL_NEAREST) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBlitFramebufferEXT(depth/stencil requires GL_NEAREST filter)");
return;
}
/* get color read/draw renderbuffers */
if (mask & GL_COLOR_BUFFER_BIT) {
const GLuint numColorDrawBuffers = ctx->DrawBuffer->_NumColorDrawBuffers;
const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer;
const struct gl_renderbuffer *colorDrawRb = NULL;
GLuint i;
/* From the EXT_framebuffer_object spec:
*
* "If a buffer is specified in <mask> and does not exist in both
* the read and draw framebuffers, the corresponding bit is silently
* ignored."
*/
if (!colorReadRb || numColorDrawBuffers == 0) {
mask &= ~GL_COLOR_BUFFER_BIT;
}
else {
for (i = 0; i < numColorDrawBuffers; i++) {
colorDrawRb = ctx->DrawBuffer->_ColorDrawBuffers[i];
if (!colorDrawRb)
continue;
/* Page 193 (page 205 of the PDF) in section 4.3.2 of the OpenGL
* ES 3.0.1 spec says:
*
* "If the source and destination buffers are identical, an
* INVALID_OPERATION error is generated. Different mipmap
* levels of a texture, different layers of a three-
* dimensional texture or two-dimensional array texture, and
* different faces of a cube map texture do not constitute
* identical buffers."
*/
if (_mesa_is_gles3(ctx) && (colorDrawRb == colorReadRb)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBlitFramebuffer(source and destination color "
"buffer cannot be the same)");
return;
}
if (!compatible_color_datatypes(colorReadRb->Format,
colorDrawRb->Format)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBlitFramebufferEXT(color buffer datatypes mismatch)");
return;
}
/* extra checks for multisample copies... */
if (readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) {
/* color formats must match */
if (!compatible_resolve_formats(colorReadRb, colorDrawRb)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBlitFramebufferEXT(bad src/dst multisample pixel formats)");
return;
}
}
}
if (filter != GL_NEAREST) {
/* From EXT_framebuffer_multisample_blit_scaled specification:
* "Calling BlitFramebuffer will result in an INVALID_OPERATION error
* if filter is not NEAREST and read buffer contains integer data."
*/
GLenum type = _mesa_get_format_datatype(colorReadRb->Format);
if (type == GL_INT || type == GL_UNSIGNED_INT) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBlitFramebufferEXT(integer color type)");
return;
}
}
}
}
if (mask & GL_STENCIL_BUFFER_BIT) {
struct gl_renderbuffer *readRb =
readFb->Attachment[BUFFER_STENCIL].Renderbuffer;
struct gl_renderbuffer *drawRb =
drawFb->Attachment[BUFFER_STENCIL].Renderbuffer;
/* From the EXT_framebuffer_object spec:
*
* "If a buffer is specified in <mask> and does not exist in both
* the read and draw framebuffers, the corresponding bit is silently
* ignored."
*/
if ((readRb == NULL) || (drawRb == NULL)) {
mask &= ~GL_STENCIL_BUFFER_BIT;
}
else {
int read_z_bits, draw_z_bits;
if (_mesa_is_gles3(ctx) && (drawRb == readRb)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBlitFramebuffer(source and destination stencil "
"buffer cannot be the same)");
return;
}
if (_mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS) !=
_mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS)) {
/* There is no need to check the stencil datatype here, because
* there is only one: GL_UNSIGNED_INT.
*/
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBlitFramebuffer(stencil attachment format mismatch)");
return;
}
read_z_bits = _mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS);
draw_z_bits = _mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS);
/* If both buffers also have depth data, the depth formats must match
* as well. If one doesn't have depth, it's not blitted, so we should
* ignore the depth format check.
*/
if (read_z_bits > 0 && draw_z_bits > 0 &&
(read_z_bits != draw_z_bits ||
_mesa_get_format_datatype(readRb->Format) !=
_mesa_get_format_datatype(drawRb->Format))) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebuffer"
"(stencil attachment depth format mismatch)");
return;
}
}
}
if (mask & GL_DEPTH_BUFFER_BIT) {
struct gl_renderbuffer *readRb =
readFb->Attachment[BUFFER_DEPTH].Renderbuffer;
struct gl_renderbuffer *drawRb =
drawFb->Attachment[BUFFER_DEPTH].Renderbuffer;
/* From the EXT_framebuffer_object spec:
*
* "If a buffer is specified in <mask> and does not exist in both
* the read and draw framebuffers, the corresponding bit is silently
* ignored."
*/
if ((readRb == NULL) || (drawRb == NULL)) {
mask &= ~GL_DEPTH_BUFFER_BIT;
}
else {
int read_s_bit, draw_s_bit;
if (_mesa_is_gles3(ctx) && (drawRb == readRb)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBlitFramebuffer(source and destination depth "
"buffer cannot be the same)");
return;
}
if ((_mesa_get_format_bits(readRb->Format, GL_DEPTH_BITS) !=
_mesa_get_format_bits(drawRb->Format, GL_DEPTH_BITS)) ||
(_mesa_get_format_datatype(readRb->Format) !=
_mesa_get_format_datatype(drawRb->Format))) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBlitFramebuffer(depth attachment format mismatch)");
return;
}
read_s_bit = _mesa_get_format_bits(readRb->Format, GL_STENCIL_BITS);
draw_s_bit = _mesa_get_format_bits(drawRb->Format, GL_STENCIL_BITS);
/* If both buffers also have stencil data, the stencil formats must
* match as well. If one doesn't have stencil, it's not blitted, so
* we should ignore the stencil format check.
*/
if (read_s_bit > 0 && draw_s_bit > 0 && read_s_bit != draw_s_bit) {
_mesa_error(ctx, GL_INVALID_OPERATION, "glBlitFramebuffer"
"(depth attachment stencil bits mismatch)");
return;
}
}
}
if (_mesa_is_gles3(ctx)) {
/* Page 194 (page 206 of the PDF) in section 4.3.2 of the OpenGL ES
* 3.0.1 spec says:
*
* "If SAMPLE_BUFFERS for the draw framebuffer is greater than zero,
* an INVALID_OPERATION error is generated."
*/
if (drawFb->Visual.samples > 0) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBlitFramebuffer(destination samples must be 0)");
return;
}
/* Page 194 (page 206 of the PDF) in section 4.3.2 of the OpenGL ES
* 3.0.1 spec says:
*
* "If SAMPLE_BUFFERS for the read framebuffer is greater than zero,
* no copy is performed and an INVALID_OPERATION error is generated
* if the formats of the read and draw framebuffers are not
* identical or if the source and destination rectangles are not
* defined with the same (X0, Y0) and (X1, Y1) bounds."
*
* The format check was made above because desktop OpenGL has the same
* requirement.
*/
if (readFb->Visual.samples > 0
&& (srcX0 != dstX0 || srcY0 != dstY0
|| srcX1 != dstX1 || srcY1 != dstY1)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBlitFramebuffer(bad src/dst multisample region)");
return;
}
} else {
if (readFb->Visual.samples > 0 &&
drawFb->Visual.samples > 0 &&
readFb->Visual.samples != drawFb->Visual.samples) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBlitFramebufferEXT(mismatched samples)");
return;
}
/* extra checks for multisample copies... */
if ((readFb->Visual.samples > 0 || drawFb->Visual.samples > 0) &&
(filter == GL_NEAREST || filter == GL_LINEAR)) {
/* src and dest region sizes must be the same */
if (abs(srcX1 - srcX0) != abs(dstX1 - dstX0) ||
abs(srcY1 - srcY0) != abs(dstY1 - dstY0)) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glBlitFramebufferEXT(bad src/dst multisample region sizes)");
return;
}
}
}
/* Debug code */
if (DEBUG_BLIT) {
const struct gl_renderbuffer *colorReadRb = readFb->_ColorReadBuffer;
const struct gl_renderbuffer *colorDrawRb = NULL;
GLuint i = 0;
printf("glBlitFramebuffer(%d, %d, %d, %d, %d, %d, %d, %d,"
" 0x%x, 0x%x)\n",
srcX0, srcY0, srcX1, srcY1,
dstX0, dstY0, dstX1, dstY1,
mask, filter);
if (colorReadRb) {
const struct gl_renderbuffer_attachment *att;
att = find_attachment(readFb, colorReadRb);
printf(" Src FBO %u RB %u (%dx%d) ",
readFb->Name, colorReadRb->Name,
colorReadRb->Width, colorReadRb->Height);
if (att && att->Texture) {
printf("Tex %u tgt 0x%x level %u face %u",
att->Texture->Name,
att->Texture->Target,
att->TextureLevel,
att->CubeMapFace);
}
printf("\n");
/* Print all active color render buffers */
for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) {
colorDrawRb = ctx->DrawBuffer->_ColorDrawBuffers[i];
if (!colorDrawRb)
continue;
att = find_attachment(drawFb, colorDrawRb);
printf(" Dst FBO %u RB %u (%dx%d) ",
drawFb->Name, colorDrawRb->Name,
colorDrawRb->Width, colorDrawRb->Height);
if (att && att->Texture) {
printf("Tex %u tgt 0x%x level %u face %u",
att->Texture->Name,
att->Texture->Target,
att->TextureLevel,
att->CubeMapFace);
}
printf("\n");
}
}
}
if (!mask ||
(srcX1 - srcX0) == 0 || (srcY1 - srcY0) == 0 ||
(dstX1 - dstX0) == 0 || (dstY1 - dstY0) == 0) {
return;
}
ASSERT(ctx->Driver.BlitFramebuffer);
ctx->Driver.BlitFramebuffer(ctx,
srcX0, srcY0, srcX1, srcY1,
dstX0, dstY0, dstX1, dstY1,
mask, filter);
}
static void static void
invalidate_framebuffer_storage(GLenum target, GLsizei numAttachments, invalidate_framebuffer_storage(GLenum target, GLsizei numAttachments,
const GLenum *attachments, GLint x, GLint y, const GLenum *attachments, GLint x, GLint y,

View File

@@ -206,11 +206,6 @@ extern void GLAPIENTRY
_mesa_GenerateMipmap(GLenum target); _mesa_GenerateMipmap(GLenum target);
extern void GLAPIENTRY
_mesa_BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter);
extern void GLAPIENTRY extern void GLAPIENTRY
_mesa_InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, _mesa_InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments,
const GLenum *attachments, GLint x, GLint y, const GLenum *attachments, GLint x, GLint y,