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");
}
}
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;
{
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_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;
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;
minHeight = MIN2(minHeight, texImg->Height);
maxHeight = MAX2(maxHeight, texImg->Height);
f = texImg->_BaseFormat;
+ baseFormat = f;
attFormat = texImg->TexFormat;
numImages++;
return;
}
- attNumSamples = texImg->NumSamples;
- attNumStorageSamples = texImg->NumSamples;
+ 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 (_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);
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);
}
/**
if (!ctx->Extensions.MESA_framebuffer_flip_y)
goto invalid_pname_enum;
cannot_be_winsys_fbo = true;
+ break;
default:
goto 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
_mesa_FramebufferParameteri(GLenum target, GLenum pname, GLint param)
{
GET_CURRENT_CONTEXT(ctx);
struct gl_framebuffer *fb;
- if (!ctx->Extensions.ARB_framebuffer_no_attachments &&
- !ctx->Extensions.ARB_sample_locations) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glFramebufferParameteriv not supported "
- "(neither ARB_framebuffer_no_attachments nor ARB_sample_locations"
- " is available)");
+ if (!validate_framebuffer_parameter_extensions(pname,
+ "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
validate_get_framebuffer_parameteriv_pname(struct gl_context *ctx,
struct gl_framebuffer *fb,
GET_CURRENT_CONTEXT(ctx);
struct gl_framebuffer *fb;
- if (!ctx->Extensions.ARB_framebuffer_no_attachments &&
- !ctx->Extensions.ARB_sample_locations) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glGetFramebufferParameteriv not supported "
- "(neither ARB_framebuffer_no_attachments nor ARB_sample_locations"
- " is available)");
+ 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
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:
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,
}
+void GLAPIENTRY
+_mesa_NamedRenderbufferStorageMultisampleEXT(GLuint renderbuffer, GLsizei samples,
+ 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,
+ "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,
}
+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;
}
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_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,
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);
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
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));
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);
}
}
_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,
}
+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");
+}
+
+
static void
get_framebuffer_attachment_parameter(struct gl_context *ctx,
struct gl_framebuffer *buffer,
}
}
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)
}
+/* 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)
}
+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,
"glInvalidateNamedFramebufferSubData");
}
-
void GLAPIENTRY
_mesa_InvalidateFramebuffer_no_error(GLenum target, GLsizei numAttachments,
const GLenum *attachments)
{
- /* no-op */
+ struct gl_framebuffer *fb;
+ GET_CURRENT_CONTEXT(ctx);
+
+ fb = get_framebuffer_target(ctx, target);
+ if (!fb)
+ return;
+
+ discard_framebuffer(ctx, fb, numAttachments, attachments);
}
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;