#include "buffers.h"
#include "context.h"
+#include "debug_output.h"
#include "enums.h"
#include "fbobject.h"
#include "formats.h"
void
_mesa_init_fbobjects(struct gl_context *ctx)
{
- mtx_init(&DummyFramebuffer.Mutex, mtx_plain);
- mtx_init(&DummyRenderbuffer.Mutex, mtx_plain);
- mtx_init(&IncompleteFramebuffer.Mutex, mtx_plain);
+ simple_mtx_init(&DummyFramebuffer.Mutex, mtx_plain);
+ simple_mtx_init(&DummyRenderbuffer.Mutex, mtx_plain);
+ simple_mtx_init(&IncompleteFramebuffer.Mutex, mtx_plain);
DummyFramebuffer.Delete = delete_dummy_framebuffer;
DummyRenderbuffer.Delete = delete_dummy_renderbuffer;
IncompleteFramebuffer.Delete = delete_dummy_framebuffer;
fb = (struct gl_framebuffer *)
_mesa_HashLookup(ctx->Shared->FrameBuffers, id);
+
+ return fb;
+}
+
+
+struct gl_framebuffer *
+_mesa_lookup_framebuffer_dsa(struct gl_context *ctx, GLuint id,
+ const char* func)
+{
+ struct gl_framebuffer *fb;
+
+ if (id == 0)
+ return NULL;
+
+ fb = _mesa_lookup_framebuffer(ctx, id);
+
+ /* Name exists but buffer is not initialized */
+ if (fb == &DummyFramebuffer) {
+ fb = ctx->Driver.NewFramebuffer(ctx, id);
+ _mesa_HashLockMutex(ctx->Shared->FrameBuffers);
+ _mesa_HashInsert(ctx->Shared->FrameBuffers, id, fb);
+ _mesa_HashUnlockMutex(ctx->Shared->BufferObjects);
+ }
+ /* Name doesn't exist */
+ else if (!fb) {
+ _mesa_HashLockMutex(ctx->Shared->FrameBuffers);
+ fb = ctx->Driver.NewFramebuffer(ctx, id);
+ if (!fb) {
+ _mesa_HashUnlockMutex(ctx->Shared->FrameBuffers);
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "%s", func);
+ return NULL;
+ }
+ _mesa_HashInsertLocked(ctx->Shared->BufferObjects, id, fb);
+ _mesa_HashUnlockMutex(ctx->Shared->BufferObjects);
+ }
return fb;
}
{
assert(_mesa_is_winsys_fbo(fb));
+ attachment = _mesa_back_to_front_if_single_buffered(fb, attachment);
+
if (_mesa_is_gles3(ctx)) {
- assert(attachment == GL_BACK ||
- attachment == GL_DEPTH ||
- attachment == GL_STENCIL);
switch (attachment) {
case GL_BACK:
/* Since there is no stereo rendering in ES 3.0, only return the
* LEFT bits.
*/
- if (ctx->DrawBuffer->Visual.doubleBufferMode)
- return &fb->Attachment[BUFFER_BACK_LEFT];
+ return &fb->Attachment[BUFFER_BACK_LEFT];
+ case GL_FRONT:
+ /* We might get this if back_to_front triggers above */
return &fb->Attachment[BUFFER_FRONT_LEFT];
case GL_DEPTH:
return &fb->Attachment[BUFFER_DEPTH];
case GL_STENCIL:
return &fb->Attachment[BUFFER_STENCIL];
+ default:
+ unreachable("invalid attachment");
}
}
return &fb->Attachment[BUFFER_BACK_LEFT];
case GL_BACK_RIGHT:
return &fb->Attachment[BUFFER_BACK_RIGHT];
+ case GL_BACK:
+ /* The ARB_ES3_1_compatibility spec says:
+ *
+ * "Since this command can only query a single framebuffer
+ * attachment, BACK is equivalent to BACK_LEFT."
+ */
+ if (ctx->Extensions.ARB_ES3_1_compatibility)
+ return &fb->Attachment[BUFFER_BACK_LEFT];
+ return NULL;
case GL_AUX0:
if (fb->Visual.numAuxBuffers == 1) {
return &fb->Attachment[BUFFER_AUX0];
rb->Height = texImage->Height2;
rb->Depth = texImage->Depth2;
rb->NumSamples = texImage->NumSamples;
+ rb->NumStorageSamples = texImage->NumSamples;
rb->TexImage = texImage;
if (driver_RenderTexture_is_safe(att))
struct gl_framebuffer *fb,
struct gl_renderbuffer_attachment *att,
struct gl_texture_object *texObj,
- GLenum texTarget, GLuint level, GLuint layer,
- GLboolean layered)
+ GLenum texTarget, GLuint level, GLsizei samples,
+ GLuint layer, GLboolean layered)
{
struct gl_renderbuffer *rb = att->Renderbuffer;
/* always update these fields */
att->TextureLevel = level;
+ att->NumSamples = samples;
att->CubeMapFace = _mesa_tex_target_to_face(texTarget);
att->Zoffset = layer;
att->Layered = layered;
{
struct gl_renderbuffer_attachment *att;
- mtx_lock(&fb->Mutex);
+ simple_mtx_lock(&fb->Mutex);
att = get_attachment(ctx, fb, attachment, NULL);
assert(att);
invalidate_framebuffer(fb);
- mtx_unlock(&fb->Mutex);
+ simple_mtx_unlock(&fb->Mutex);
}
{
static GLuint msg_id;
- _mesa_gl_debug(ctx, &msg_id,
- MESA_DEBUG_SOURCE_API,
- MESA_DEBUG_TYPE_OTHER,
- MESA_DEBUG_SEVERITY_MEDIUM,
- "FBO incomplete: %s [%d]\n", msg, index);
+ _mesa_gl_debugf(ctx, &msg_id,
+ MESA_DEBUG_SOURCE_API,
+ MESA_DEBUG_TYPE_OTHER,
+ MESA_DEBUG_SEVERITY_MEDIUM,
+ "FBO incomplete: %s [%d]\n", msg, index);
if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) {
_mesa_debug(NULL, "FBO Incomplete: %s [%d]\n", msg, index);
/* Reject additional cases for GLES */
switch (internalFormat) {
+ case GL_R8_SNORM:
+ case GL_RG8_SNORM:
case GL_RGBA8_SNORM:
+ return _mesa_has_EXT_render_snorm(ctx);
+ case GL_R16_SNORM:
+ case GL_RG16_SNORM:
+ case GL_RGBA16_SNORM:
+ return _mesa_has_EXT_texture_norm16(ctx) &&
+ _mesa_has_EXT_render_snorm(ctx);
case GL_RGB32F:
case GL_RGB32I:
case GL_RGB32UI:
case GL_RGB8I:
case GL_RGB8UI:
case GL_SRGB8:
+ case GL_RGB10:
case GL_RGB9_E5:
- case GL_RG8_SNORM:
- case GL_R8_SNORM:
+ case GL_SR8_EXT:
return GL_FALSE;
default:
break;
}
- if (format == MESA_FORMAT_B10G10R10A2_UNORM &&
- internalFormat != GL_RGB10_A2) {
+ if (internalFormat != GL_RGB10_A2 &&
+ (format == MESA_FORMAT_B10G10R10A2_UNORM ||
+ format == MESA_FORMAT_B10G10R10X2_UNORM ||
+ format == MESA_FORMAT_R10G10B10A2_UNORM ||
+ format == MESA_FORMAT_R10G10B10X2_UNORM)) {
return GL_FALSE;
}
/* Look for reasons why the attachment might be incomplete */
if (att->Type == GL_TEXTURE) {
const struct gl_texture_object *texObj = att->Texture;
- struct gl_texture_image *texImage;
+ const struct gl_texture_image *texImage;
GLenum baseFormat;
if (!texObj) {
* these textures to be used as a render target, this is done via
* GL_EXT_color_buffer(_half)_float with set of new sized types.
*/
- if (_mesa_is_gles(ctx) && (texImage->TexObject->_IsFloat ||
- texImage->TexObject->_IsHalfFloat)) {
+ if (_mesa_is_gles(ctx) && (texObj->_IsFloat || texObj->_IsHalfFloat)) {
att_incomplete("bad internal format");
att->Complete = GL_FALSE;
return;
GLuint numImages;
GLenum intFormat = GL_NONE; /* color buffers' internal format */
GLuint minWidth = ~0, minHeight = ~0, maxWidth = 0, maxHeight = 0;
- GLint numSamples = -1;
+ GLint numColorSamples = -1;
+ GLint numColorStorageSamples = -1;
+ GLint numDepthSamples = -1;
GLint fixedSampleLocations = -1;
GLint i;
GLuint j;
fb->_HasSNormOrFloatColorBuffer = GL_FALSE;
fb->_HasAttachments = true;
fb->_IntegerBuffers = 0;
+ fb->_RGBBuffers = 0;
+ fb->_FP32Buffers = 0;
/* Start at -2 to more easily loop over all attachment points.
* -2: depth buffer
for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) {
struct gl_renderbuffer_attachment *att;
GLenum f;
+ GLenum baseFormat;
mesa_format attFormat;
GLenum att_tex_target = GL_NONE;
/* get width, height, format of the renderbuffer/texture
*/
+ unsigned attNumSamples, attNumStorageSamples;
+
if (att->Type == GL_TEXTURE) {
const struct gl_texture_image *texImg = att->Renderbuffer->TexImage;
att_tex_target = att->Texture->Target;
minHeight = MIN2(minHeight, texImg->Height);
maxHeight = MAX2(maxHeight, texImg->Height);
f = texImg->_BaseFormat;
+ baseFormat = f;
attFormat = texImg->TexFormat;
numImages++;
return;
}
- if (numSamples < 0)
- numSamples = texImg->NumSamples;
- else if (numSamples != texImg->NumSamples) {
- fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
- fbo_incomplete(ctx, "inconsistent sample count", -1);
- return;
- }
-
if (fixedSampleLocations < 0)
fixedSampleLocations = texImg->FixedSampleLocations;
else if (fixedSampleLocations != texImg->FixedSampleLocations) {
fbo_incomplete(ctx, "inconsistent fixed sample locations", -1);
return;
}
+
+ if (att->NumSamples > 0)
+ attNumSamples = att->NumSamples;
+ else
+ attNumSamples = texImg->NumSamples;
+ attNumStorageSamples = attNumSamples;
}
else if (att->Type == GL_RENDERBUFFER_EXT) {
minWidth = MIN2(minWidth, att->Renderbuffer->Width);
minHeight = MIN2(minHeight, att->Renderbuffer->Height);
maxHeight = MAX2(minHeight, att->Renderbuffer->Height);
f = att->Renderbuffer->InternalFormat;
+ baseFormat = att->Renderbuffer->_BaseFormat;
attFormat = att->Renderbuffer->Format;
numImages++;
- if (numSamples < 0)
- numSamples = att->Renderbuffer->NumSamples;
- else if (numSamples != att->Renderbuffer->NumSamples) {
- fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
- fbo_incomplete(ctx, "inconsistent sample count", -1);
- return;
- }
-
/* RENDERBUFFER has fixedSampleLocations implicitly true */
if (fixedSampleLocations < 0)
fixedSampleLocations = GL_TRUE;
fbo_incomplete(ctx, "inconsistent fixed sample locations", -1);
return;
}
+
+ attNumSamples = att->Renderbuffer->NumSamples;
+ attNumStorageSamples = att->Renderbuffer->NumStorageSamples;
}
else {
assert(att->Type == GL_NONE);
continue;
}
+ if (i >= 0) {
+ /* Color buffers. */
+ if (numColorSamples < 0) {
+ assert(numColorStorageSamples < 0);
+ numColorSamples = attNumSamples;
+ numColorStorageSamples = attNumStorageSamples;
+ } else if (numColorSamples != attNumSamples ||
+ numColorStorageSamples != attNumStorageSamples) {
+ fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
+ fbo_incomplete(ctx, "inconsistent sample counts", -1);
+ return;
+ }
+ } else {
+ /* Depth/stencil buffers. */
+ if (numDepthSamples < 0) {
+ numDepthSamples = attNumSamples;
+ } else if (numDepthSamples != attNumSamples) {
+ fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
+ fbo_incomplete(ctx, "inconsistent sample counts", -1);
+ return;
+ }
+ }
+
/* Update flags describing color buffer datatypes */
if (i >= 0) {
GLenum type = _mesa_get_format_datatype(attFormat);
if (_mesa_is_format_integer_color(attFormat))
fb->_IntegerBuffers |= (1 << i);
+ if (baseFormat == GL_RGB)
+ fb->_RGBBuffers |= (1 << i);
+
+ if (type == GL_FLOAT && _mesa_get_format_max_bits(attFormat) > 16)
+ fb->_FP32Buffers |= (1 << i);
+
fb->_AllColorBuffersFixedPoint =
fb->_AllColorBuffersFixedPoint &&
(type == GL_UNSIGNED_NORMALIZED || type == GL_SIGNED_NORMALIZED);
*/
}
+ if (ctx->Extensions.AMD_framebuffer_multisample_advanced) {
+ /* See if non-matching sample counts are supported. */
+ if (numColorSamples >= 0 && numDepthSamples >= 0) {
+ bool found = false;
+
+ assert(numColorStorageSamples != -1);
+
+ numColorSamples = MAX2(numColorSamples, 1);
+ numColorStorageSamples = MAX2(numColorStorageSamples, 1);
+ numDepthSamples = MAX2(numDepthSamples, 1);
+
+ if (numColorSamples == 1 && numColorStorageSamples == 1 &&
+ numDepthSamples == 1) {
+ found = true;
+ } else {
+ for (i = 0; i < ctx->Const.NumSupportedMultisampleModes; i++) {
+ GLint *counts =
+ &ctx->Const.SupportedMultisampleModes[i].NumColorSamples;
+
+ if (counts[0] == numColorSamples &&
+ counts[1] == numColorStorageSamples &&
+ counts[2] == numDepthSamples) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
+ fbo_incomplete(ctx, "unsupported sample counts", -1);
+ return;
+ }
+ }
+ } else {
+ /* If the extension is unsupported, all sample counts must be equal. */
+ if (numColorSamples >= 0 &&
+ (numColorSamples != numColorStorageSamples ||
+ (numDepthSamples >= 0 && numColorSamples != numDepthSamples))) {
+ fb->_Status = GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE;
+ fbo_incomplete(ctx, "inconsistent sample counts", -1);
+ return;
+ }
+ }
+
fb->MaxNumLayers = max_layer_count;
if (numImages == 0) {
static void
-bind_renderbuffer(GLenum target, GLuint renderbuffer, bool allow_user_names)
+bind_renderbuffer(GLenum target, GLuint renderbuffer)
{
struct gl_renderbuffer *newRb;
GET_CURRENT_CONTEXT(ctx);
/* ID was reserved, but no real renderbuffer object made yet */
newRb = NULL;
}
- else if (!newRb && !allow_user_names) {
+ else if (!newRb && ctx->API == API_OPENGL_CORE) {
/* All RB IDs must be Gen'd */
- _mesa_error(ctx, GL_INVALID_OPERATION, "glBindRenderbuffer(buffer)");
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindRenderbuffer(non-gen name)");
return;
}
void GLAPIENTRY
_mesa_BindRenderbuffer(GLenum target, GLuint renderbuffer)
{
- GET_CURRENT_CONTEXT(ctx);
-
/* OpenGL ES glBindRenderbuffer and glBindRenderbufferOES use this same
* entry point, but they allow the use of user-generated names.
*/
- bind_renderbuffer(target, renderbuffer, _mesa_is_gles(ctx));
+ bind_renderbuffer(target, renderbuffer);
}
void GLAPIENTRY
_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
{
- /* This function should not be in the dispatch table for core profile /
- * OpenGL 3.1, so execution should never get here in those cases -- no
- * need for an explicit test.
- */
- bind_renderbuffer(target, renderbuffer, true);
+ bind_renderbuffer(target, renderbuffer);
}
/**
- * ARB_framebuffer_no_attachment - Application passes requested param's
- * here. NOTE: NumSamples requested need not be _NumSamples which is
- * what the hw supports.
+ * ARB_framebuffer_no_attachment and ARB_sample_locations - Application passes
+ * requested param's here. NOTE: NumSamples requested need not be _NumSamples
+ * which is what the hw supports.
*/
static void
framebuffer_parameteri(struct gl_context *ctx, struct gl_framebuffer *fb,
GLenum pname, GLint param, const char *func)
{
+ bool cannot_be_winsys_fbo = false;
+
+ switch (pname) {
+ case GL_FRAMEBUFFER_DEFAULT_WIDTH:
+ case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
+ case GL_FRAMEBUFFER_DEFAULT_LAYERS:
+ case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
+ case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
+ if (!ctx->Extensions.ARB_framebuffer_no_attachments)
+ goto invalid_pname_enum;
+ cannot_be_winsys_fbo = true;
+ break;
+ case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB:
+ case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB:
+ if (!ctx->Extensions.ARB_sample_locations)
+ goto invalid_pname_enum;
+ break;
+ case GL_FRAMEBUFFER_FLIP_Y_MESA:
+ if (!ctx->Extensions.MESA_framebuffer_flip_y)
+ goto invalid_pname_enum;
+ cannot_be_winsys_fbo = true;
+ break;
+ default:
+ goto invalid_pname_enum;
+ }
+
+ if (cannot_be_winsys_fbo && _mesa_is_winsys_fbo(fb)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(invalid pname=0x%x for default framebuffer)", func, pname);
+ return;
+ }
+
switch (pname) {
case GL_FRAMEBUFFER_DEFAULT_WIDTH:
if (param < 0 || param > ctx->Const.MaxFramebufferWidth)
case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
fb->DefaultGeometry.FixedSampleLocations = param;
break;
+ case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB:
+ fb->ProgrammableSampleLocations = !!param;
+ break;
+ case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB:
+ fb->SampleLocationPixelGrid = !!param;
+ break;
+ case GL_FRAMEBUFFER_FLIP_Y_MESA:
+ fb->FlipY = param;
+ break;
+ }
+
+ switch (pname) {
+ case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB:
+ case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB:
+ if (fb == ctx->DrawBuffer)
+ ctx->NewDriverState |= ctx->DriverFlags.NewSampleLocations;
+ break;
default:
- _mesa_error(ctx, GL_INVALID_ENUM,
- "%s(pname=0x%x)", func, pname);
+ invalidate_framebuffer(fb);
+ ctx->NewState |= _NEW_BUFFERS;
+ break;
}
- invalidate_framebuffer(fb);
- ctx->NewState |= _NEW_BUFFERS;
+ return;
+
+invalid_pname_enum:
+ _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname);
+}
+
+static bool
+validate_framebuffer_parameter_extensions(GLenum pname, const char *func)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (!ctx->Extensions.ARB_framebuffer_no_attachments &&
+ !ctx->Extensions.ARB_sample_locations &&
+ !ctx->Extensions.MESA_framebuffer_flip_y) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s not supported "
+ "(none of ARB_framebuffer_no_attachments,"
+ " ARB_sample_locations, or"
+ " MESA_framebuffer_flip_y extensions are available)",
+ func);
+ return false;
+ }
+
+ /*
+ * If only the MESA_framebuffer_flip_y extension is enabled
+ * pname can only be GL_FRAMEBUFFER_FLIP_Y_MESA
+ */
+ if (ctx->Extensions.MESA_framebuffer_flip_y &&
+ pname != GL_FRAMEBUFFER_FLIP_Y_MESA &&
+ !(ctx->Extensions.ARB_framebuffer_no_attachments ||
+ ctx->Extensions.ARB_sample_locations)) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname);
+ return false;
+ }
+
+ return true;
}
void GLAPIENTRY
GET_CURRENT_CONTEXT(ctx);
struct gl_framebuffer *fb;
- if (!ctx->Extensions.ARB_framebuffer_no_attachments) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glFramebufferParameteriv not supported "
- "(ARB_framebuffer_no_attachments not implemented)");
+ if (!validate_framebuffer_parameter_extensions(pname,
+ "glFramebufferParameteri")) {
return;
}
return;
}
- /* check framebuffer binding */
- if (_mesa_is_winsys_fbo(fb)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glFramebufferParameteri");
- return;
- }
-
framebuffer_parameteri(ctx, fb, pname, param, "glFramebufferParameteri");
}
+void GLAPIENTRY
+_mesa_FramebufferParameteriMESA(GLenum target, GLenum pname, GLint param)
+{
+ _mesa_FramebufferParameteri(target, pname, param);
+}
+
static bool
-_pname_valid_for_default_framebuffer(struct gl_context *ctx,
- GLenum pname)
+validate_get_framebuffer_parameteriv_pname(struct gl_context *ctx,
+ struct gl_framebuffer *fb,
+ GLuint pname, const char *func)
{
- if (!_mesa_is_desktop_gl(ctx))
- return false;
+ bool cannot_be_winsys_fbo = true;
switch (pname) {
+ case GL_FRAMEBUFFER_DEFAULT_LAYERS:
+ /*
+ * According to the OpenGL ES 3.1 specification section 9.2.3, the
+ * GL_FRAMEBUFFER_LAYERS parameter name is not supported.
+ */
+ if (_mesa_is_gles31(ctx) && !ctx->Extensions.OES_geometry_shader) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname);
+ return false;
+ }
+ break;
+ case GL_FRAMEBUFFER_DEFAULT_WIDTH:
+ case GL_FRAMEBUFFER_DEFAULT_HEIGHT:
+ case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
+ case GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS:
+ break;
case GL_DOUBLEBUFFER:
case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
case GL_IMPLEMENTATION_COLOR_READ_TYPE:
case GL_SAMPLES:
case GL_SAMPLE_BUFFERS:
case GL_STEREO:
- return true;
+ /* From OpenGL 4.5 spec, section 9.2.3 "Framebuffer Object Queries:
+ *
+ * "An INVALID_OPERATION error is generated by GetFramebufferParameteriv
+ * if the default framebuffer is bound to target and pname is not one
+ * of the accepted values from table 23.73, other than
+ * SAMPLE_POSITION."
+ *
+ * For OpenGL ES, using default framebuffer raises INVALID_OPERATION
+ * for any pname.
+ */
+ cannot_be_winsys_fbo = !_mesa_is_desktop_gl(ctx);
+ break;
+ case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB:
+ case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB:
+ if (!ctx->Extensions.ARB_sample_locations)
+ goto invalid_pname_enum;
+ cannot_be_winsys_fbo = false;
+ break;
+ case GL_FRAMEBUFFER_FLIP_Y_MESA:
+ if (!ctx->Extensions.MESA_framebuffer_flip_y) {
+ _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname);
+ return false;
+ }
+ break;
default:
+ goto invalid_pname_enum;
+ }
+
+ if (cannot_be_winsys_fbo && _mesa_is_winsys_fbo(fb)) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(invalid pname=0x%x for default framebuffer)", func, pname);
return false;
}
+
+ return true;
+
+invalid_pname_enum:
+ _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname);
+ return false;
}
static void
get_framebuffer_parameteriv(struct gl_context *ctx, struct gl_framebuffer *fb,
GLenum pname, GLint *params, const char *func)
{
- /* From OpenGL 4.5 spec, section 9.2.3 "Framebuffer Object Queries:
- *
- * "An INVALID_OPERATION error is generated by GetFramebufferParameteriv
- * if the default framebuffer is bound to target and pname is not one
- * of the accepted values from table 23.73, other than
- * SAMPLE_POSITION."
- *
- * For OpenGL ES, using default framebuffer still raises INVALID_OPERATION
- * for any pname.
- */
- if (_mesa_is_winsys_fbo(fb) &&
- !_pname_valid_for_default_framebuffer(ctx, pname)) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(invalid pname=0x%x for default framebuffer)", func, pname);
+ if (!validate_get_framebuffer_parameteriv_pname(ctx, fb, pname, func))
return;
- }
switch (pname) {
case GL_FRAMEBUFFER_DEFAULT_WIDTH:
*params = fb->DefaultGeometry.Height;
break;
case GL_FRAMEBUFFER_DEFAULT_LAYERS:
- /*
- * According to the OpenGL ES 3.1 specification section 9.2.3, the
- * GL_FRAMEBUFFER_LAYERS parameter name is not supported.
- */
- if (_mesa_is_gles31(ctx) && !ctx->Extensions.OES_geometry_shader) {
- _mesa_error(ctx, GL_INVALID_ENUM, "%s(pname=0x%x)", func, pname);
- break;
- }
*params = fb->DefaultGeometry.Layers;
break;
case GL_FRAMEBUFFER_DEFAULT_SAMPLES:
case GL_STEREO:
*params = fb->Visual.stereoMode;
break;
- default:
- _mesa_error(ctx, GL_INVALID_ENUM,
- "%s(pname=0x%x)", func, pname);
+ case GL_FRAMEBUFFER_PROGRAMMABLE_SAMPLE_LOCATIONS_ARB:
+ *params = fb->ProgrammableSampleLocations;
+ break;
+ case GL_FRAMEBUFFER_SAMPLE_LOCATION_PIXEL_GRID_ARB:
+ *params = fb->SampleLocationPixelGrid;
+ break;
+ case GL_FRAMEBUFFER_FLIP_Y_MESA:
+ *params = fb->FlipY;
+ break;
}
}
GET_CURRENT_CONTEXT(ctx);
struct gl_framebuffer *fb;
- if (!ctx->Extensions.ARB_framebuffer_no_attachments) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glGetFramebufferParameteriv not supported "
- "(ARB_framebuffer_no_attachments not implemented)");
+ if (!validate_framebuffer_parameter_extensions(pname,
+ "glGetFramebufferParameteriv")) {
return;
}
"glGetFramebufferParameteriv");
}
+void GLAPIENTRY
+_mesa_GetFramebufferParameterivMESA(GLenum target, GLenum pname, GLint *params)
+{
+ _mesa_GetFramebufferParameteriv(target, pname, params);
+}
/**
* Remove the specified renderbuffer or texture from any attachment point in
}
+void GLAPIENTRY
+_mesa_GenRenderbuffers_no_error(GLsizei n, GLuint *renderbuffers)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ create_render_buffers(ctx, n, renderbuffers, false);
+}
+
+
void GLAPIENTRY
_mesa_GenRenderbuffers(GLsizei n, GLuint *renderbuffers)
{
}
+void GLAPIENTRY
+_mesa_CreateRenderbuffers_no_error(GLsizei n, GLuint *renderbuffers)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ create_render_buffers(ctx, n, renderbuffers, true);
+}
+
+
void GLAPIENTRY
_mesa_CreateRenderbuffers(GLsizei n, GLuint *renderbuffers)
{
* \return the base internal format, or 0 if internalFormat is illegal
*/
GLenum
-_mesa_base_fbo_format(struct gl_context *ctx, GLenum internalFormat)
+_mesa_base_fbo_format(const struct gl_context *ctx, GLenum internalFormat)
{
/*
* Notes: some formats such as alpha, luminance, etc. were added
case GL_RGBA:
case GL_RGBA2:
case GL_RGBA12:
- case GL_RGBA16:
return _mesa_is_desktop_gl(ctx) ? GL_RGBA : 0;
+ case GL_RGBA16:
+ return _mesa_is_desktop_gl(ctx) || _mesa_has_EXT_texture_norm16(ctx)
+ ? GL_RGBA : 0;
case GL_RGB10_A2:
case GL_SRGB8_ALPHA8_EXT:
return _mesa_is_desktop_gl(ctx) || _mesa_is_gles3(ctx) ? GL_RGBA : 0;
ctx->Extensions.ARB_depth_buffer_float)
? GL_DEPTH_STENCIL : 0;
case GL_RED:
+ return _mesa_has_ARB_texture_rg(ctx) ? GL_RED : 0;
case GL_R16:
- return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_rg
+ return _mesa_has_ARB_texture_rg(ctx) || _mesa_has_EXT_texture_norm16(ctx)
? GL_RED : 0;
case GL_R8:
return ctx->API != API_OPENGLES && ctx->Extensions.ARB_texture_rg
? GL_RED : 0;
case GL_RG:
+ return _mesa_has_ARB_texture_rg(ctx) ? GL_RG : 0;
case GL_RG16:
- return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_rg
+ return _mesa_has_ARB_texture_rg(ctx) || _mesa_has_EXT_texture_norm16(ctx)
? GL_RG : 0;
case GL_RG8:
return ctx->API != API_OPENGLES && ctx->Extensions.ARB_texture_rg
? GL_RG : 0;
/* signed normalized texture formats */
- case GL_RED_SNORM:
case GL_R8_SNORM:
+ return _mesa_has_EXT_texture_snorm(ctx) || _mesa_has_EXT_render_snorm(ctx)
+ ? GL_RED : 0;
+ case GL_RED_SNORM:
+ return _mesa_has_EXT_texture_snorm(ctx) ? GL_RED : 0;
case GL_R16_SNORM:
- return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm
+ return _mesa_has_EXT_texture_snorm(ctx) ||
+ (_mesa_has_EXT_render_snorm(ctx) &&
+ _mesa_has_EXT_texture_norm16(ctx))
? GL_RED : 0;
- case GL_RG_SNORM:
case GL_RG8_SNORM:
+ return _mesa_has_EXT_texture_snorm(ctx) || _mesa_has_EXT_render_snorm(ctx)
+ ? GL_RG : 0;
+ case GL_RG_SNORM:
+ return _mesa_has_EXT_texture_snorm(ctx) ? GL_RG : 0;
case GL_RG16_SNORM:
- return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm
+ return _mesa_has_EXT_texture_snorm(ctx) ||
+ (_mesa_has_EXT_render_snorm(ctx) &&
+ _mesa_has_EXT_texture_norm16(ctx))
? GL_RG : 0;
case GL_RGB_SNORM:
case GL_RGB8_SNORM:
case GL_RGB16_SNORM:
return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm
? GL_RGB : 0;
- case GL_RGBA_SNORM:
case GL_RGBA8_SNORM:
+ return _mesa_has_EXT_texture_snorm(ctx) || _mesa_has_EXT_render_snorm(ctx)
+ ? GL_RGBA : 0;
+ case GL_RGBA_SNORM:
+ return _mesa_has_EXT_texture_snorm(ctx) ? GL_RGBA : 0;
case GL_RGBA16_SNORM:
- return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_snorm
+ return _mesa_has_EXT_texture_snorm(ctx) ||
+ (_mesa_has_EXT_render_snorm(ctx) &&
+ _mesa_has_EXT_texture_norm16(ctx))
? GL_RGBA : 0;
case GL_ALPHA_SNORM:
case GL_ALPHA8_SNORM:
ctx->Extensions.ARB_texture_float) ||
_mesa_is_gles3(ctx) /* EXT_color_buffer_float */ )
? GL_RGBA : 0;
+ case GL_RGB9_E5:
+ return (_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_shared_exponent)
+ ? GL_RGB: 0;
case GL_ALPHA16F_ARB:
case GL_ALPHA32F_ARB:
return ctx->API == API_OPENGL_COMPAT &&
void
_mesa_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
GLenum internalFormat, GLsizei width,
- GLsizei height, GLsizei samples)
+ GLsizei height, GLsizei samples,
+ GLsizei storageSamples)
{
const GLenum baseFormat = _mesa_base_fbo_format(ctx, internalFormat);
if (samples != 0) {
assert(samples > 0);
assert(_mesa_check_sample_count(ctx, GL_RENDERBUFFER,
- internalFormat, samples) == GL_NO_ERROR);
+ internalFormat, samples,
+ storageSamples) == GL_NO_ERROR);
}
FLUSH_VERTICES(ctx, _NEW_BUFFERS);
if (rb->InternalFormat == internalFormat &&
rb->Width == (GLuint) width &&
rb->Height == (GLuint) height &&
- rb->NumSamples == samples) {
+ rb->NumSamples == samples &&
+ rb->NumStorageSamples == storageSamples) {
/* no change in allocation needed */
return;
}
/* These MUST get set by the AllocStorage func */
rb->Format = MESA_FORMAT_NONE;
rb->NumSamples = samples;
+ rb->NumStorageSamples = storageSamples;
/* Now allocate the storage */
assert(rb->AllocStorage);
rb->InternalFormat = GL_NONE;
rb->_BaseFormat = GL_NONE;
rb->NumSamples = 0;
+ rb->NumStorageSamples = 0;
}
/* Invalidate the framebuffers the renderbuffer is attached in. */
static void
renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
GLenum internalFormat, GLsizei width,
- GLsizei height, GLsizei samples, const char *func)
+ GLsizei height, GLsizei samples, GLsizei storageSamples,
+ const char *func)
{
GLenum baseFormat;
GLenum sample_count_error;
if (samples == NO_SAMPLES) {
/* NumSamples == 0 indicates non-multisampling */
samples = 0;
+ storageSamples = 0;
}
else {
/* check the sample count;
* note: driver may choose to use more samples than what's requested
*/
sample_count_error = _mesa_check_sample_count(ctx, GL_RENDERBUFFER,
- internalFormat, samples);
+ internalFormat, samples, storageSamples);
/* Section 2.5 (GL Errors) of OpenGL 3.0 specification, page 16:
*
* "If a negative number is provided where an argument of type sizei or
* sizeiptr is specified, the error INVALID VALUE is generated."
*/
- if (samples < 0) {
+ if (samples < 0 || storageSamples < 0) {
sample_count_error = GL_INVALID_VALUE;
}
if (sample_count_error != GL_NO_ERROR) {
- _mesa_error(ctx, sample_count_error, "%s(samples=%d)", func, samples);
+ _mesa_error(ctx, sample_count_error,
+ "%s(samples=%d, storageSamples=%d)", func, samples,
+ storageSamples);
return;
}
}
- _mesa_renderbuffer_storage(ctx, rb, internalFormat, width, height, samples);
+ _mesa_renderbuffer_storage(ctx, rb, internalFormat, width, height, samples,
+ storageSamples);
}
/**
static void
renderbuffer_storage_named(GLuint renderbuffer, GLenum internalFormat,
GLsizei width, GLsizei height, GLsizei samples,
- const char *func)
+ GLsizei storageSamples, const char *func)
{
GET_CURRENT_CONTEXT(ctx);
return;
}
- renderbuffer_storage(ctx, rb, internalFormat, width, height, samples, func);
+ renderbuffer_storage(ctx, rb, internalFormat, width, height, samples,
+ storageSamples, func);
}
/**
static void
renderbuffer_storage_target(GLenum target, GLenum internalFormat,
GLsizei width, GLsizei height, GLsizei samples,
- const char *func)
+ GLsizei storageSamples, const char *func)
{
GET_CURRENT_CONTEXT(ctx);
}
renderbuffer_storage(ctx, ctx->CurrentRenderbuffer, internalFormat, width,
- height, samples, func);
+ height, samples, storageSamples, func);
}
* a token value here just for error reporting purposes.
*/
renderbuffer_storage_target(target, internalFormat, width, height,
- NO_SAMPLES, "glRenderbufferStorage");
+ NO_SAMPLES, 0, "glRenderbufferStorage");
}
GLsizei width, GLsizei height)
{
renderbuffer_storage_target(target, internalFormat, width, height,
- samples, "glRenderbufferStorageMultisample");
+ samples, samples,
+ "glRenderbufferStorageMultisample");
+}
+
+
+void GLAPIENTRY
+_mesa_RenderbufferStorageMultisampleAdvancedAMD(
+ GLenum target, GLsizei samples, GLsizei storageSamples,
+ GLenum internalFormat, GLsizei width, GLsizei height)
+{
+ renderbuffer_storage_target(target, internalFormat, width, height,
+ samples, storageSamples,
+ "glRenderbufferStorageMultisampleAdvancedAMD");
}
break;
}
- renderbuffer_storage_target(target, internalFormat, width, height, 0,
+ renderbuffer_storage_target(target, internalFormat, width, height, 0, 0,
"glRenderbufferStorageEXT");
}
* a token value here just for error reporting purposes.
*/
renderbuffer_storage_named(renderbuffer, internalformat, width, height,
- NO_SAMPLES, "glNamedRenderbufferStorage");
+ NO_SAMPLES, 0, "glNamedRenderbufferStorage");
+}
+
+void GLAPIENTRY
+_mesa_NamedRenderbufferStorageEXT(GLuint renderbuffer, GLenum internalformat,
+ GLsizei width, GLsizei height)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
+ if (!rb || rb == &DummyRenderbuffer) {
+ _mesa_HashLockMutex(ctx->Shared->RenderBuffers);
+ rb = allocate_renderbuffer_locked(ctx, renderbuffer, "glNamedRenderbufferStorageEXT");
+ _mesa_HashUnlockMutex(ctx->Shared->RenderBuffers);
+ }
+ renderbuffer_storage(ctx, rb, internalformat, width, height, NO_SAMPLES,
+ 0, "glNamedRenderbufferStorageEXT");
}
+
void GLAPIENTRY
_mesa_NamedRenderbufferStorageMultisample(GLuint renderbuffer, GLsizei samples,
GLenum internalformat,
GLsizei width, GLsizei height)
{
renderbuffer_storage_named(renderbuffer, internalformat, width, height,
- samples,
+ samples, samples,
"glNamedRenderbufferStorageMultisample");
}
-static void
-get_render_buffer_parameteriv(struct gl_context *ctx,
- struct gl_renderbuffer *rb, GLenum pname,
- GLint *params, const char *func)
+void GLAPIENTRY
+_mesa_NamedRenderbufferStorageMultisampleEXT(GLuint renderbuffer, GLsizei samples,
+ GLenum internalformat,
+ GLsizei width, GLsizei height)
{
- /* No need to flush here since we're just quering state which is
- * not effected by rendering.
- */
-
- switch (pname) {
- case GL_RENDERBUFFER_WIDTH_EXT:
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
+ if (!rb || rb == &DummyRenderbuffer) {
+ _mesa_HashLockMutex(ctx->Shared->RenderBuffers);
+ rb = allocate_renderbuffer_locked(ctx, renderbuffer,
+ "glNamedRenderbufferStorageMultisampleEXT");
+ _mesa_HashUnlockMutex(ctx->Shared->RenderBuffers);
+ }
+ renderbuffer_storage(ctx, rb, internalformat, width, height,
+ samples, samples,
+ "glNamedRenderbufferStorageMultisample");
+}
+
+
+void GLAPIENTRY
+_mesa_NamedRenderbufferStorageMultisampleAdvancedAMD(
+ GLuint renderbuffer, GLsizei samples, GLsizei storageSamples,
+ GLenum internalformat, GLsizei width, GLsizei height)
+{
+ renderbuffer_storage_named(renderbuffer, internalformat, width, height,
+ samples, storageSamples,
+ "glNamedRenderbufferStorageMultisampleAdvancedAMD");
+}
+
+
+static void
+get_render_buffer_parameteriv(struct gl_context *ctx,
+ struct gl_renderbuffer *rb, GLenum pname,
+ GLint *params, const char *func)
+{
+ /* No need to flush here since we're just quering state which is
+ * not effected by rendering.
+ */
+
+ switch (pname) {
+ case GL_RENDERBUFFER_WIDTH_EXT:
*params = rb->Width;
return;
case GL_RENDERBUFFER_HEIGHT_EXT:
case GL_RENDERBUFFER_DEPTH_SIZE_EXT:
case GL_RENDERBUFFER_STENCIL_SIZE_EXT:
*params = get_component_bits(pname, rb->_BaseFormat, rb->Format);
- break;
+ return;
case GL_RENDERBUFFER_SAMPLES:
if ((_mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_framebuffer_object)
|| _mesa_is_gles3(ctx)) {
*params = rb->NumSamples;
- break;
+ return;
}
- /* fallthrough */
- default:
- _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid pname=%s)", func,
- _mesa_enum_to_string(pname));
- return;
+ break;
+ case GL_RENDERBUFFER_STORAGE_SAMPLES_AMD:
+ if (ctx->Extensions.AMD_framebuffer_multisample_advanced) {
+ *params = rb->NumStorageSamples;
+ return;
+ }
+ break;
}
+
+ _mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid pname=%s)", func,
+ _mesa_enum_to_string(pname));
}
}
+void GLAPIENTRY
+_mesa_GetNamedRenderbufferParameterivEXT(GLuint renderbuffer, GLenum pname,
+ GLint *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ struct gl_renderbuffer *rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
+ if (!rb || rb == &DummyRenderbuffer) {
+ _mesa_HashLockMutex(ctx->Shared->RenderBuffers);
+ rb = allocate_renderbuffer_locked(ctx, renderbuffer, "glGetNamedRenderbufferParameterivEXT");
+ _mesa_HashUnlockMutex(ctx->Shared->RenderBuffers);
+ }
+
+ get_render_buffer_parameteriv(ctx, rb, pname, params,
+ "glGetNamedRenderbufferParameterivEXT");
+}
+
+
GLboolean GLAPIENTRY
_mesa_IsFramebuffer(GLuint framebuffer)
{
static void
-bind_framebuffer(GLenum target, GLuint framebuffer, bool allow_user_names)
+bind_framebuffer(GLenum target, GLuint framebuffer)
{
struct gl_framebuffer *newDrawFb, *newReadFb;
GLboolean bindReadBuf, bindDrawBuf;
/* ID was reserved, but no real framebuffer object made yet */
newDrawFb = NULL;
}
- else if (!newDrawFb && !allow_user_names) {
+ else if (!newDrawFb && ctx->API == API_OPENGL_CORE) {
/* All FBO IDs must be Gen'd */
- _mesa_error(ctx, GL_INVALID_OPERATION, "glBindFramebuffer(buffer)");
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glBindFramebuffer(non-gen name)");
return;
}
if (bindDrawBuf) {
FLUSH_VERTICES(ctx, _NEW_BUFFERS);
+ ctx->NewDriverState |= ctx->DriverFlags.NewSampleLocations;
/* check if old framebuffer had any texture attachments */
if (oldDrawFb)
check_begin_texture_render(ctx, newDrawFb);
_mesa_reference_framebuffer(&ctx->DrawBuffer, newDrawFb);
+ _mesa_update_allow_draw_out_of_order(ctx);
}
if ((bindDrawBuf || bindReadBuf) && ctx->Driver.BindFramebuffer) {
void GLAPIENTRY
_mesa_BindFramebuffer(GLenum target, GLuint framebuffer)
{
- GET_CURRENT_CONTEXT(ctx);
-
/* OpenGL ES glBindFramebuffer and glBindFramebufferOES use this same entry
* point, but they allow the use of user-generated names.
*/
- bind_framebuffer(target, framebuffer, _mesa_is_gles(ctx));
+ bind_framebuffer(target, framebuffer);
}
void GLAPIENTRY
_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
{
- /* This function should not be in the dispatch table for core profile /
- * OpenGL 3.1, so execution should never get here in those cases -- no
- * need for an explicit test.
- */
- bind_framebuffer(target, framebuffer, true);
+ bind_framebuffer(target, framebuffer);
}
}
+GLenum GLAPIENTRY
+_mesa_CheckFramebufferStatus_no_error(GLenum target)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ struct gl_framebuffer *fb = get_framebuffer_target(ctx, target);
+ return _mesa_check_framebuffer_status(ctx, fb);
+}
+
+
GLenum GLAPIENTRY
_mesa_CheckFramebufferStatus(GLenum target)
{
}
+GLenum GLAPIENTRY
+_mesa_CheckNamedFramebufferStatusEXT(GLuint framebuffer, GLenum target)
+{
+ struct gl_framebuffer *fb;
+ GET_CURRENT_CONTEXT(ctx);
+
+ switch (target) {
+ case GL_DRAW_FRAMEBUFFER:
+ case GL_FRAMEBUFFER:
+ case GL_READ_FRAMEBUFFER:
+ break;
+ default:
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glCheckNamedFramebufferStatusEXT(invalid target %s)",
+ _mesa_enum_to_string(target));
+ return 0;
+ }
+
+ if (framebuffer == 0) {
+ return _mesa_CheckNamedFramebufferStatus(0, target);
+ }
+
+ fb = _mesa_lookup_framebuffer_dsa(ctx, framebuffer,
+ "glCheckNamedFramebufferStatusEXT");
+ if (!fb)
+ return 0;
+
+ return _mesa_check_framebuffer_status(ctx, fb);
+}
+
+
/**
* Replicate the src attachment point. Used by framebuffer_texture() when
* the same texture is attached at GL_DEPTH_ATTACHMENT and
case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
return true;
case GL_TEXTURE_CUBE_MAP:
- /* We don't need to check the extension (GL_ARB_direct_state_access) or
- * GL version (4.5) for GL_TEXTURE_CUBE_MAP because DSA is always
- * enabled in core profile. This can be called from
- * _mesa_FramebufferTextureLayer in compatibility profile (OpenGL 3.0),
- * so we do have to check the profile.
+ /* GL_TEXTURE_CUBE_MAP is only allowed by OpenGL 4.5 here, which
+ * includes the DSA API.
+ *
+ * Because DSA is only enabled for GL 3.1+ and this can be called
+ * from _mesa_FramebufferTextureLayer in compatibility profile,
+ * we need to check the version.
*/
- return ctx->API == API_OPENGL_CORE;
+ return _mesa_is_desktop_gl(ctx) && ctx->Version >= 31;
}
_mesa_error(ctx, GL_INVALID_OPERATION,
* and layer is negative."
*/
if (layer < 0) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "%s(layer %u < 0)", caller, layer);
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(layer %d < 0)", caller, layer);
return false;
}
* \return true if no errors, false if errors
*/
static bool
-check_level(struct gl_context *ctx, GLenum target, GLint level,
- const char *caller)
+check_level(struct gl_context *ctx, struct gl_texture_object *texObj,
+ GLenum target, GLint level, const char *caller)
{
- if ((level < 0) ||
- (level >= _mesa_max_texture_levels(ctx, target))) {
+ /* Section 9.2.8 of the OpenGL 4.6 specification says:
+ *
+ * "If texture refers to an immutable-format texture, level must be
+ * greater than or equal to zero and smaller than the value of
+ * TEXTURE_VIEW_NUM_LEVELS for texture."
+ */
+ const int max_levels = texObj->Immutable ? texObj->ImmutableLevels :
+ _mesa_max_texture_levels(ctx, target);
+
+ if (level < 0 || level >= max_levels) {
_mesa_error(ctx, GL_INVALID_VALUE,
"%s(invalid level %d)", caller, level);
return false;
GLenum attachment,
struct gl_renderbuffer_attachment *att,
struct gl_texture_object *texObj, GLenum textarget,
- GLint level, GLuint layer, GLboolean layered)
+ GLint level, GLsizei samples,
+ GLuint layer, GLboolean layered)
{
FLUSH_VERTICES(ctx, _NEW_BUFFERS);
- mtx_lock(&fb->Mutex);
+ simple_mtx_lock(&fb->Mutex);
if (texObj) {
if (attachment == GL_DEPTH_ATTACHMENT &&
texObj == fb->Attachment[BUFFER_STENCIL].Texture &&
level == fb->Attachment[BUFFER_STENCIL].TextureLevel &&
_mesa_tex_target_to_face(textarget) ==
fb->Attachment[BUFFER_STENCIL].CubeMapFace &&
+ samples == fb->Attachment[BUFFER_STENCIL].NumSamples &&
layer == fb->Attachment[BUFFER_STENCIL].Zoffset) {
/* The texture object is already attached to the stencil attachment
* point. Don't create a new renderbuffer; just reuse the stencil
level == fb->Attachment[BUFFER_DEPTH].TextureLevel &&
_mesa_tex_target_to_face(textarget) ==
fb->Attachment[BUFFER_DEPTH].CubeMapFace &&
+ samples == fb->Attachment[BUFFER_DEPTH].NumSamples &&
layer == fb->Attachment[BUFFER_DEPTH].Zoffset) {
/* As above, but with depth and stencil transposed. */
reuse_framebuffer_texture_attachment(fb, BUFFER_STENCIL,
BUFFER_DEPTH);
} else {
set_texture_attachment(ctx, fb, att, texObj, textarget,
- level, layer, layered);
+ level, samples, layer, layered);
if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) {
/* Above we created a new renderbuffer and attached it to the
invalidate_framebuffer(fb);
- mtx_unlock(&fb->Mutex);
+ simple_mtx_unlock(&fb->Mutex);
}
get_attachment(ctx, fb, attachment, NULL);
_mesa_framebuffer_texture(ctx, fb, attachment, att, texObj, textarget,
- level, layer, GL_FALSE);
+ level, 0, layer, GL_FALSE);
}
static void
-framebuffer_texture_with_dims(int dims, GLenum target,
+framebuffer_texture_with_dims(int dims, GLenum target, GLuint framebuffer,
GLenum attachment, GLenum textarget,
- GLuint texture, GLint level, GLint layer,
- const char *caller)
+ GLuint texture, GLint level, GLsizei samples,
+ GLint layer, const char *caller, bool dsa)
{
GET_CURRENT_CONTEXT(ctx);
struct gl_framebuffer *fb;
struct gl_texture_object *texObj;
/* Get the framebuffer object */
- fb = get_framebuffer_target(ctx, target);
+ if (dsa) {
+ fb = _mesa_lookup_framebuffer_dsa(ctx, framebuffer, caller);
+ } else {
+ fb = get_framebuffer_target(ctx, target);
+ }
if (!fb) {
_mesa_error(ctx, GL_INVALID_ENUM, "%s(invalid target %s)", caller,
_mesa_enum_to_string(target));
if ((dims == 3) && !check_layer(ctx, texObj->Target, layer, caller))
return;
- if (!check_level(ctx, textarget, level, caller))
+ if (!check_level(ctx, texObj, textarget, level, caller))
return;
}
return;
_mesa_framebuffer_texture(ctx, fb, attachment, att, texObj, textarget,
- level, layer, GL_FALSE);
+ level, samples, layer, GL_FALSE);
}
_mesa_FramebufferTexture1D(GLenum target, GLenum attachment,
GLenum textarget, GLuint texture, GLint level)
{
- framebuffer_texture_with_dims(1, target, attachment, textarget, texture,
- level, 0, "glFramebufferTexture1D");
+ framebuffer_texture_with_dims(1, target, 0, attachment, textarget, texture,
+ level, 0, 0, "glFramebufferTexture1D", false);
}
_mesa_FramebufferTexture2D(GLenum target, GLenum attachment,
GLenum textarget, GLuint texture, GLint level)
{
- framebuffer_texture_with_dims(2, target, attachment, textarget, texture,
- level, 0, "glFramebufferTexture2D");
+ framebuffer_texture_with_dims(2, target, 0, attachment, textarget, texture,
+ level, 0, 0, "glFramebufferTexture2D", false);
+}
+
+
+void GLAPIENTRY
+_mesa_FramebufferTexture2DMultisampleEXT(GLenum target, GLenum attachment,
+ GLenum textarget, GLuint texture,
+ GLint level, GLsizei samples)
+{
+ framebuffer_texture_with_dims(2, target, 0, attachment, textarget, texture,
+ level, samples, 0,
+ "glFramebufferTexture2DMultisampleEXT",
+ false);
}
GLenum textarget, GLuint texture,
GLint level, GLint layer)
{
- framebuffer_texture_with_dims(3, target, attachment, textarget, texture,
- level, layer, "glFramebufferTexture3D");
+ framebuffer_texture_with_dims(3, target, 0, attachment, textarget, texture,
+ level, 0, layer, "glFramebufferTexture3D", false);
}
return;
}
- if (!check_level(ctx, texObj->Target, level, func))
+ if (!check_level(ctx, texObj, texObj->Target, level, func))
return;
}
}
_mesa_framebuffer_texture(ctx, fb, attachment, att, texObj, textarget,
- level, layer, layered);
+ level, 0, layer, layered);
}
void GLAPIENTRY
}
+void GLAPIENTRY
+_mesa_NamedFramebufferTexture1DEXT(GLuint framebuffer, GLenum attachment,
+ GLenum textarget, GLuint texture, GLint level)
+{
+ framebuffer_texture_with_dims(1, GL_FRAMEBUFFER, framebuffer, attachment,
+ textarget, texture, level, 0, 0,
+ "glNamedFramebufferTexture1DEXT", true);
+}
+
+
+void GLAPIENTRY
+_mesa_NamedFramebufferTexture2DEXT(GLuint framebuffer, GLenum attachment,
+ GLenum textarget, GLuint texture, GLint level)
+{
+ framebuffer_texture_with_dims(2, GL_FRAMEBUFFER, framebuffer, attachment,
+ textarget, texture, level, 0, 0,
+ "glNamedFramebufferTexture2DEXT", true);
+}
+
+
+void GLAPIENTRY
+_mesa_NamedFramebufferTexture3DEXT(GLuint framebuffer, GLenum attachment,
+ GLenum textarget, GLuint texture,
+ GLint level, GLint zoffset)
+{
+ framebuffer_texture_with_dims(3, GL_FRAMEBUFFER, framebuffer, attachment,
+ textarget, texture, level, 0, zoffset,
+ "glNamedFramebufferTexture3DEXT", true);
+}
+
+
void
_mesa_framebuffer_renderbuffer(struct gl_context *ctx,
struct gl_framebuffer *fb,
_mesa_update_framebuffer_visual(ctx, fb);
}
-static void
-framebuffer_renderbuffer(struct gl_context *ctx,
- struct gl_framebuffer *fb,
- GLenum attachment,
- struct gl_renderbuffer *rb,
- const char *func)
+static ALWAYS_INLINE void
+framebuffer_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb,
+ GLenum attachment, GLenum renderbuffertarget,
+ GLuint renderbuffer, const char *func, bool no_error)
{
struct gl_renderbuffer_attachment *att;
+ struct gl_renderbuffer *rb;
bool is_color_attachment;
- if (_mesa_is_winsys_fbo(fb)) {
- /* Can't attach new renderbuffers to a window system framebuffer */
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(window-system framebuffer)", func);
+ if (!no_error && renderbuffertarget != GL_RENDERBUFFER) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "%s(renderbuffertarget is not GL_RENDERBUFFER)", func);
return;
}
- att = get_attachment(ctx, fb, attachment, &is_color_attachment);
- if (att == NULL) {
- /*
- * From OpenGL 4.5 spec, section 9.2.7 "Attaching Renderbuffer Images to
- * a Framebuffer":
- *
- * "An INVALID_OPERATION error is generated if attachment is COLOR_-
- * ATTACHMENTm where m is greater than or equal to the value of
- * MAX_COLOR_- ATTACHMENTS ."
- *
- * If we are at this point, is because the attachment is not valid, so
- * if is_color_attachment is true, is because of the previous reason.
- */
- if (is_color_attachment) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(invalid color attachment %s)", func,
- _mesa_enum_to_string(attachment));
+ if (renderbuffer) {
+ if (!no_error) {
+ rb = _mesa_lookup_renderbuffer_err(ctx, renderbuffer, func);
+ if (!rb)
+ return;
} else {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "%s(invalid attachment %s)", func,
- _mesa_enum_to_string(attachment));
+ rb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
}
-
- return;
+ } else {
+ /* remove renderbuffer attachment */
+ rb = NULL;
}
- if (attachment == GL_DEPTH_STENCIL_ATTACHMENT &&
- rb && rb->Format != MESA_FORMAT_NONE) {
- /* make sure the renderbuffer is a depth/stencil format */
- const GLenum baseFormat = _mesa_get_format_base_format(rb->Format);
- if (baseFormat != GL_DEPTH_STENCIL) {
+ if (!no_error) {
+ if (_mesa_is_winsys_fbo(fb)) {
+ /* Can't attach new renderbuffers to a window system framebuffer */
_mesa_error(ctx, GL_INVALID_OPERATION,
- "%s(renderbuffer is not DEPTH_STENCIL format)", func);
+ "%s(window-system framebuffer)", func);
+ return;
+ }
+
+ att = get_attachment(ctx, fb, attachment, &is_color_attachment);
+ if (att == NULL) {
+ /*
+ * From OpenGL 4.5 spec, section 9.2.7 "Attaching Renderbuffer Images
+ * to a Framebuffer":
+ *
+ * "An INVALID_OPERATION error is generated if attachment is
+ * COLOR_- ATTACHMENTm where m is greater than or equal to the
+ * value of MAX_COLOR_- ATTACHMENTS ."
+ *
+ * If we are at this point, is because the attachment is not valid, so
+ * if is_color_attachment is true, is because of the previous reason.
+ */
+ if (is_color_attachment) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(invalid color attachment %s)", func,
+ _mesa_enum_to_string(attachment));
+ } else {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "%s(invalid attachment %s)", func,
+ _mesa_enum_to_string(attachment));
+ }
+
return;
}
+
+ if (attachment == GL_DEPTH_STENCIL_ATTACHMENT &&
+ rb && rb->Format != MESA_FORMAT_NONE) {
+ /* make sure the renderbuffer is a depth/stencil format */
+ const GLenum baseFormat = _mesa_get_format_base_format(rb->Format);
+ if (baseFormat != GL_DEPTH_STENCIL) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s(renderbuffer is not DEPTH_STENCIL format)", func);
+ return;
+ }
+ }
}
_mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb);
}
+static void
+framebuffer_renderbuffer_error(struct gl_context *ctx,
+ struct gl_framebuffer *fb, GLenum attachment,
+ GLenum renderbuffertarget,
+ GLuint renderbuffer, const char *func)
+{
+ framebuffer_renderbuffer(ctx, fb, attachment, renderbuffertarget,
+ renderbuffer, func, false);
+}
+
+static void
+framebuffer_renderbuffer_no_error(struct gl_context *ctx,
+ struct gl_framebuffer *fb, GLenum attachment,
+ GLenum renderbuffertarget,
+ GLuint renderbuffer, const char *func)
+{
+ framebuffer_renderbuffer(ctx, fb, attachment, renderbuffertarget,
+ renderbuffer, func, true);
+}
+
+void GLAPIENTRY
+_mesa_FramebufferRenderbuffer_no_error(GLenum target, GLenum attachment,
+ GLenum renderbuffertarget,
+ GLuint renderbuffer)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ struct gl_framebuffer *fb = get_framebuffer_target(ctx, target);
+ framebuffer_renderbuffer_no_error(ctx, fb, attachment, renderbuffertarget,
+ renderbuffer, "glFramebufferRenderbuffer");
+}
+
void GLAPIENTRY
_mesa_FramebufferRenderbuffer(GLenum target, GLenum attachment,
GLenum renderbuffertarget,
GLuint renderbuffer)
{
struct gl_framebuffer *fb;
- struct gl_renderbuffer *rb;
GET_CURRENT_CONTEXT(ctx);
fb = get_framebuffer_target(ctx, target);
return;
}
- if (renderbuffertarget != GL_RENDERBUFFER) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glFramebufferRenderbuffer(renderbuffertarget is not "
- "GL_RENDERBUFFER)");
- return;
- }
+ framebuffer_renderbuffer_error(ctx, fb, attachment, renderbuffertarget,
+ renderbuffer, "glFramebufferRenderbuffer");
+}
- if (renderbuffer) {
- rb = _mesa_lookup_renderbuffer_err(ctx, renderbuffer,
- "glFramebufferRenderbuffer");
- if (!rb)
- return;
- }
- else {
- /* remove renderbuffer attachment */
- rb = NULL;
- }
+void GLAPIENTRY
+_mesa_NamedFramebufferRenderbuffer_no_error(GLuint framebuffer,
+ GLenum attachment,
+ GLenum renderbuffertarget,
+ GLuint renderbuffer)
+{
+ GET_CURRENT_CONTEXT(ctx);
- framebuffer_renderbuffer(ctx, fb, attachment, rb,
- "glFramebufferRenderbuffer");
+ struct gl_framebuffer *fb = _mesa_lookup_framebuffer(ctx, framebuffer);
+ framebuffer_renderbuffer_no_error(ctx, fb, attachment, renderbuffertarget,
+ renderbuffer,
+ "glNamedFramebufferRenderbuffer");
}
-
void GLAPIENTRY
_mesa_NamedFramebufferRenderbuffer(GLuint framebuffer, GLenum attachment,
GLenum renderbuffertarget,
GLuint renderbuffer)
{
struct gl_framebuffer *fb;
- struct gl_renderbuffer *rb;
GET_CURRENT_CONTEXT(ctx);
fb = _mesa_lookup_framebuffer_err(ctx, framebuffer,
if (!fb)
return;
- if (renderbuffertarget != GL_RENDERBUFFER) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glNamedFramebufferRenderbuffer(renderbuffertarget is not "
- "GL_RENDERBUFFER)");
- return;
- }
+ framebuffer_renderbuffer_error(ctx, fb, attachment, renderbuffertarget,
+ renderbuffer,
+ "glNamedFramebufferRenderbuffer");
+}
- if (renderbuffer) {
- rb = _mesa_lookup_renderbuffer_err(ctx, renderbuffer,
- "glNamedFramebufferRenderbuffer");
- if (!rb)
- return;
- }
- else {
- /* remove renderbuffer attachment */
- rb = NULL;
- }
- framebuffer_renderbuffer(ctx, fb, attachment, rb,
- "glNamedFramebufferRenderbuffer");
+void GLAPIENTRY
+_mesa_NamedFramebufferRenderbufferEXT(GLuint framebuffer, GLenum attachment,
+ GLenum renderbuffertarget,
+ GLuint renderbuffer)
+{
+ struct gl_framebuffer *fb;
+ GET_CURRENT_CONTEXT(ctx);
+
+ fb = _mesa_lookup_framebuffer_dsa(ctx, framebuffer,
+ "glNamedFramebufferRenderbufferEXT");
+ if (!fb)
+ return;
+
+ framebuffer_renderbuffer_error(ctx, fb, attachment, renderbuffertarget,
+ renderbuffer,
+ "glNamedFramebufferRenderbuffer");
}
}
}
else {
- if (ctx->Extensions.EXT_framebuffer_sRGB) {
- *params =
- _mesa_get_format_color_encoding(att->Renderbuffer->Format);
+ if (ctx->Extensions.EXT_sRGB) {
+ *params = (_mesa_is_format_srgb(att->Renderbuffer->Format) ?
+ GL_SRGB : GL_LINEAR);
}
else {
/* According to ARB_framebuffer_sRGB, we should return LINEAR
goto invalid_pname_enum;
}
return;
+ case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT:
+ if (!ctx->Extensions.EXT_multisampled_render_to_texture) {
+ goto invalid_pname_enum;
+ } else if (att->Type == GL_TEXTURE) {
+ *params = att->NumSamples;
+ } else if (att->Type == GL_NONE) {
+ _mesa_error(ctx, err, "%s(invalid pname %s)", caller,
+ _mesa_enum_to_string(pname));
+ } else {
+ goto invalid_pname_enum;
+ }
+ return;
default:
goto invalid_pname_enum;
}
}
+void GLAPIENTRY
+_mesa_GetNamedFramebufferAttachmentParameterivEXT(GLuint framebuffer,
+ GLenum attachment,
+ GLenum pname, GLint *params)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_framebuffer *buffer;
+
+ if (framebuffer) {
+ buffer = _mesa_lookup_framebuffer_dsa(ctx, framebuffer,
+ "glGetNamedFramebufferAttachmentParameterivEXT");
+ if (!buffer)
+ return;
+ }
+ else {
+ /*
+ * Section 9.2 Binding and Managing Framebuffer Objects of the OpenGL
+ * 4.5 core spec (30.10.2014, PDF page 314):
+ * "If framebuffer is zero, then the default draw framebuffer is
+ * queried."
+ */
+ buffer = ctx->WinSysDrawBuffer;
+ }
+
+ get_framebuffer_attachment_parameter(ctx, buffer, attachment, pname,
+ params,
+ "glGetNamedFramebufferAttachmentParameterivEXT");
+}
+
+
void GLAPIENTRY
_mesa_NamedFramebufferParameteri(GLuint framebuffer, GLenum pname,
GLint param)
GET_CURRENT_CONTEXT(ctx);
struct gl_framebuffer *fb = NULL;
- if (!ctx->Extensions.ARB_framebuffer_no_attachments) {
+ if (!ctx->Extensions.ARB_framebuffer_no_attachments &&
+ !ctx->Extensions.ARB_sample_locations) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glNamedFramebufferParameteri("
- "ARB_framebuffer_no_attachments not implemented)");
+ "neither ARB_framebuffer_no_attachments nor "
+ "ARB_sample_locations is available)");
return;
}
- fb = _mesa_lookup_framebuffer_err(ctx, framebuffer,
- "glNamedFramebufferParameteri");
+ if (framebuffer) {
+ fb = _mesa_lookup_framebuffer_err(ctx, framebuffer,
+ "glNamedFramebufferParameteri");
+ } else {
+ fb = ctx->WinSysDrawBuffer;
+ }
if (fb) {
framebuffer_parameteri(ctx, fb, pname, param,
}
+/* Helper function for ARB_framebuffer_no_attachments functions interacting with EXT_direct_state_access */
+static struct gl_framebuffer *
+lookup_named_framebuffer_ext_dsa(struct gl_context *ctx, GLuint framebuffer, const char* caller)
+{
+ struct gl_framebuffer *fb = NULL;
+
+ if (framebuffer) {
+ /* The ARB_framebuffer_no_attachments spec says:
+ *
+ * "The error INVALID_VALUE is generated if <framebuffer> is not
+ * a name returned by GenFramebuffers. If a framebuffer object
+ * named <framebuffer> does not yet exist, it will be created."
+ *
+ * This is different from the EXT_direct_state_access spec which says:
+ *
+ * "If the framebuffer object named by the framebuffer parameter has not
+ * been previously bound or has been deleted since the last binding,
+ * the GL first creates a new state vector in the same manner as when
+ * BindFramebuffer creates a new framebuffer object"
+ *
+ * So first we verify that the name exists.
+ */
+ fb = _mesa_lookup_framebuffer(ctx, framebuffer);
+ if (!fb) {
+ _mesa_error(ctx, GL_INVALID_VALUE, "%s(frameBuffer)", caller);
+ return NULL;
+ }
+ /* Then, make sure it's initialized */
+ if (fb == &DummyFramebuffer) {
+ fb = ctx->Driver.NewFramebuffer(ctx, framebuffer);
+ _mesa_HashLockMutex(ctx->Shared->FrameBuffers);
+ _mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, fb);
+ _mesa_HashUnlockMutex(ctx->Shared->BufferObjects);
+ }
+ }
+ else
+ fb = ctx->WinSysDrawBuffer;
+
+ return fb;
+}
+
+
+void GLAPIENTRY
+_mesa_NamedFramebufferParameteriEXT(GLuint framebuffer, GLenum pname,
+ GLint param)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_framebuffer *fb =
+ lookup_named_framebuffer_ext_dsa(ctx, framebuffer,
+ "glNamedFramebufferParameteriEXT");
+
+ if (!fb)
+ return;
+
+ framebuffer_parameteri(ctx, fb, pname, param,
+ "glNamedFramebufferParameteriEXT");
+}
+
+
+void GLAPIENTRY
+_mesa_GetFramebufferParameterivEXT(GLuint framebuffer, GLenum pname,
+ GLint *param)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_framebuffer *fb;
+
+ if (framebuffer)
+ fb = _mesa_lookup_framebuffer_dsa(ctx, framebuffer,
+ "glGetFramebufferParameterivEXT");
+ else
+ fb = ctx->WinSysDrawBuffer;
+
+ if (fb) {
+ /* The GL_EXT_direct_state_access says:
+ *
+ * The pname parameter must be one of framebuffer dependent values
+ * listed in either table 4.nnn (namely DRAW_BUFFER, READ_BUFFER,
+ * or DRAW_BUFFER0 through DRAW_BUFFER15).
+ */
+ if (pname == GL_DRAW_BUFFER) {
+ *param = fb->ColorDrawBuffer[0];
+
+ }
+ else if (pname == GL_READ_BUFFER) {
+ *param = fb->ColorReadBuffer;
+ }
+ else if (GL_DRAW_BUFFER0 <= pname && pname <= GL_DRAW_BUFFER15) {
+ *param = fb->ColorDrawBuffer[pname - GL_DRAW_BUFFER0];
+ }
+ else {
+ _mesa_error(ctx, GL_INVALID_ENUM, "glGetFramebufferParameterivEXT(pname)");
+ }
+ }
+}
+
+
void GLAPIENTRY
_mesa_GetNamedFramebufferParameteriv(GLuint framebuffer, GLenum pname,
GLint *param)
if (!ctx->Extensions.ARB_framebuffer_no_attachments) {
_mesa_error(ctx, GL_INVALID_OPERATION,
"glNamedFramebufferParameteriv("
- "ARB_framebuffer_no_attachments not implemented)");
+ "neither ARB_framebuffer_no_attachments nor ARB_sample_locations"
+ " is available)");
return;
}
- if (framebuffer) {
+ if (framebuffer)
fb = _mesa_lookup_framebuffer_err(ctx, framebuffer,
"glGetNamedFramebufferParameteriv");
- } else {
+ else
fb = ctx->WinSysDrawBuffer;
- }
if (fb) {
get_framebuffer_parameteriv(ctx, fb, pname, param,
}
+void GLAPIENTRY
+_mesa_GetNamedFramebufferParameterivEXT(GLuint framebuffer, GLenum pname,
+ GLint *param)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ struct gl_framebuffer *fb =
+ lookup_named_framebuffer_ext_dsa(ctx, framebuffer,
+ "glGetNamedFramebufferParameterivEXT");
+
+ if (!fb)
+ return;
+
+ get_framebuffer_parameteriv(ctx, fb, pname, param,
+ "glGetNamedFramebufferParameterivEXT");
+}
+
+
static void
invalidate_framebuffer_storage(struct gl_context *ctx,
struct gl_framebuffer *fb,
return;
}
+static struct gl_renderbuffer_attachment *
+get_fb_attachment(struct gl_context *ctx, struct gl_framebuffer *fb,
+ const GLenum attachment)
+{
+ switch (attachment) {
+ case GL_COLOR:
+ return &fb->Attachment[BUFFER_BACK_LEFT];
+ case GL_COLOR_ATTACHMENT0:
+ case GL_COLOR_ATTACHMENT1:
+ case GL_COLOR_ATTACHMENT2:
+ case GL_COLOR_ATTACHMENT3:
+ case GL_COLOR_ATTACHMENT4:
+ case GL_COLOR_ATTACHMENT5:
+ case GL_COLOR_ATTACHMENT6:
+ case GL_COLOR_ATTACHMENT7:
+ case GL_COLOR_ATTACHMENT8:
+ case GL_COLOR_ATTACHMENT9:
+ case GL_COLOR_ATTACHMENT10:
+ case GL_COLOR_ATTACHMENT11:
+ case GL_COLOR_ATTACHMENT12:
+ case GL_COLOR_ATTACHMENT13:
+ case GL_COLOR_ATTACHMENT14:
+ case GL_COLOR_ATTACHMENT15: {
+ const unsigned i = attachment - GL_COLOR_ATTACHMENT0;
+ if (i >= ctx->Const.MaxColorAttachments)
+ return NULL;
+ return &fb->Attachment[BUFFER_COLOR0 + i];
+ }
+ case GL_DEPTH:
+ case GL_DEPTH_ATTACHMENT:
+ case GL_DEPTH_STENCIL_ATTACHMENT:
+ return &fb->Attachment[BUFFER_DEPTH];
+ case GL_STENCIL:
+ case GL_STENCIL_ATTACHMENT:
+ return &fb->Attachment[BUFFER_STENCIL];
+ default:
+ return NULL;
+ }
+}
+
+static void
+discard_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb,
+ GLsizei numAttachments, const GLenum *attachments)
+{
+ if (!ctx->Driver.DiscardFramebuffer)
+ return;
+
+ for (int i = 0; i < numAttachments; i++) {
+ struct gl_renderbuffer_attachment *att =
+ get_fb_attachment(ctx, fb, attachments[i]);
+
+ if (!att)
+ continue;
+
+ /* If we're asked to invalidate just depth or just stencil, but the
+ * attachment is packed depth/stencil, then we can only use
+ * Driver.DiscardFramebuffer if the attachments list includes both depth
+ * and stencil and they both point at the same renderbuffer.
+ */
+ if ((attachments[i] == GL_DEPTH_ATTACHMENT ||
+ attachments[i] == GL_STENCIL_ATTACHMENT) &&
+ (!att->Renderbuffer ||
+ att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL)) {
+ GLenum other_format = (attachments[i] == GL_DEPTH_ATTACHMENT ?
+ GL_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT);
+ bool has_both = false;
+ for (int j = 0; j < numAttachments; j++) {
+ if (attachments[j] == other_format) {
+ has_both = true;
+ break;
+ }
+ }
+
+ if (fb->Attachment[BUFFER_DEPTH].Renderbuffer !=
+ fb->Attachment[BUFFER_STENCIL].Renderbuffer || !has_both)
+ continue;
+ }
+
+ ctx->Driver.DiscardFramebuffer(ctx, fb, att);
+ }
+}
+
+void GLAPIENTRY
+_mesa_InvalidateSubFramebuffer_no_error(GLenum target, GLsizei numAttachments,
+ const GLenum *attachments, GLint x,
+ GLint y, GLsizei width, GLsizei height)
+{
+ /* no-op */
+}
+
void GLAPIENTRY
_mesa_InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments,
"glInvalidateNamedFramebufferSubData");
}
+void GLAPIENTRY
+_mesa_InvalidateFramebuffer_no_error(GLenum target, GLsizei numAttachments,
+ const GLenum *attachments)
+{
+ struct gl_framebuffer *fb;
+ GET_CURRENT_CONTEXT(ctx);
+
+ fb = get_framebuffer_target(ctx, target);
+ if (!fb)
+ return;
+
+ discard_framebuffer(ctx, fb, numAttachments, attachments);
+}
+
void GLAPIENTRY
_mesa_InvalidateFramebuffer(GLenum target, GLsizei numAttachments,
ctx->Const.MaxViewportWidth,
ctx->Const.MaxViewportHeight,
"glInvalidateFramebuffer");
+
+ discard_framebuffer(ctx, fb, numAttachments, attachments);
}
}
}
- if (ctx->Driver.DiscardFramebuffer)
- ctx->Driver.DiscardFramebuffer(ctx, target, numAttachments, attachments);
+ discard_framebuffer(ctx, fb, numAttachments, attachments);
return;
"glDiscardFramebufferEXT(attachment %s)",
_mesa_enum_to_string(attachments[i]));
}
+
+static void
+sample_locations(struct gl_context *ctx, struct gl_framebuffer *fb,
+ GLuint start, GLsizei count, const GLfloat *v, bool no_error,
+ const char *name)
+{
+ GLsizei i;
+
+ if (!no_error) {
+ if (!ctx->Extensions.ARB_sample_locations) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "%s not supported "
+ "(ARB_sample_locations not available)", name);
+ return;
+ }
+
+ if (start + count > MAX_SAMPLE_LOCATION_TABLE_SIZE) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "%s(start+size > sample location table size)", name);
+ return;
+ }
+ }
+
+ if (!fb->SampleLocationTable) {
+ size_t size = MAX_SAMPLE_LOCATION_TABLE_SIZE * 2 * sizeof(GLfloat);
+ fb->SampleLocationTable = malloc(size);
+ if (!fb->SampleLocationTable) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY,
+ "Cannot allocate sample location table");
+ return;
+ }
+ for (i = 0; i < MAX_SAMPLE_LOCATION_TABLE_SIZE * 2; i++)
+ fb->SampleLocationTable[i] = 0.5f;
+ }
+
+ for (i = 0; i < count * 2; i++) {
+ /* The ARB_sample_locations spec says:
+ *
+ * Sample locations outside of [0,1] result in undefined
+ * behavior.
+ *
+ * To simplify driver implementations, we choose to clamp to
+ * [0,1] and change NaN into 0.5.
+ */
+ if (isnan(v[i]) || v[i] < 0.0f || v[i] > 1.0f) {
+ static GLuint msg_id = 0;
+ static const char* msg = "Invalid sample location specified";
+ _mesa_debug_get_id(&msg_id);
+
+ _mesa_log_msg(ctx, MESA_DEBUG_SOURCE_API, MESA_DEBUG_TYPE_UNDEFINED,
+ msg_id, MESA_DEBUG_SEVERITY_HIGH, strlen(msg), msg);
+ }
+
+ if (isnan(v[i]))
+ fb->SampleLocationTable[start * 2 + i] = 0.5f;
+ else
+ fb->SampleLocationTable[start * 2 + i] = CLAMP(v[i], 0.0f, 1.0f);
+ }
+
+ if (fb == ctx->DrawBuffer)
+ ctx->NewDriverState |= ctx->DriverFlags.NewSampleLocations;
+}
+
+void GLAPIENTRY
+_mesa_FramebufferSampleLocationsfvARB(GLenum target, GLuint start,
+ GLsizei count, const GLfloat *v)
+{
+ struct gl_framebuffer *fb;
+
+ GET_CURRENT_CONTEXT(ctx);
+
+ fb = get_framebuffer_target(ctx, target);
+ if (!fb) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glFramebufferSampleLocationsfvARB(target %s)",
+ _mesa_enum_to_string(target));
+ return;
+ }
+
+ sample_locations(ctx, fb, start, count, v, false,
+ "glFramebufferSampleLocationsfvARB");
+}
+
+void GLAPIENTRY
+_mesa_NamedFramebufferSampleLocationsfvARB(GLuint framebuffer, GLuint start,
+ GLsizei count, const GLfloat *v)
+{
+ struct gl_framebuffer *fb;
+
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (framebuffer) {
+ fb = _mesa_lookup_framebuffer_err(ctx, framebuffer,
+ "glNamedFramebufferSampleLocationsfvARB");
+ if (!fb)
+ return;
+ }
+ else
+ fb = ctx->WinSysDrawBuffer;
+
+ sample_locations(ctx, fb, start, count, v, false,
+ "glNamedFramebufferSampleLocationsfvARB");
+}
+
+void GLAPIENTRY
+_mesa_FramebufferSampleLocationsfvARB_no_error(GLenum target, GLuint start,
+ GLsizei count, const GLfloat *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ sample_locations(ctx, get_framebuffer_target(ctx, target), start,
+ count, v, true, "glFramebufferSampleLocationsfvARB");
+}
+
+void GLAPIENTRY
+_mesa_NamedFramebufferSampleLocationsfvARB_no_error(GLuint framebuffer,
+ GLuint start, GLsizei count,
+ const GLfloat *v)
+{
+ GET_CURRENT_CONTEXT(ctx);
+ sample_locations(ctx, _mesa_lookup_framebuffer(ctx, framebuffer), start,
+ count, v, true, "glNamedFramebufferSampleLocationsfvARB");
+}
+
+void GLAPIENTRY
+_mesa_EvaluateDepthValuesARB(void)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ if (!ctx->Extensions.ARB_sample_locations) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "EvaluateDepthValuesARB not supported (neither "
+ "ARB_sample_locations nor NV_sample_locations is available)");
+ return;
+ }
+
+ if (ctx->Driver.EvaluateDepthValues)
+ ctx->Driver.EvaluateDepthValues(ctx);
+}