*/
+#include "buffers.h"
#include "context.h"
#include "fbobject.h"
#include "framebuffer.h"
#include "hash.h"
+#include "mipmap.h"
#include "renderbuffer.h"
#include "state.h"
#include "teximage.h"
if (att->Type == GL_TEXTURE || att->Type == GL_RENDERBUFFER_EXT) {
ASSERT(att->Renderbuffer);
ASSERT(!att->Texture);
- att->Renderbuffer->RefCount--;
- if (att->Renderbuffer->RefCount == 0) {
- att->Renderbuffer->Delete(att->Renderbuffer);
- }
- att->Renderbuffer = NULL;
+ _mesa_reference_renderbuffer(&att->Renderbuffer, NULL);
}
att->Type = GL_NONE;
att->Complete = GL_TRUE;
/* XXX check if re-doing same attachment, exit early */
_mesa_remove_attachment(ctx, att);
att->Type = GL_RENDERBUFFER_EXT;
- att->Renderbuffer = rb;
att->Texture = NULL; /* just to be safe */
att->Complete = GL_FALSE;
- rb->RefCount++;
+ _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
}
struct gl_renderbuffer_attachment *att;
_glthread_LOCK_MUTEX(fb->Mutex);
- if (rb)
- _glthread_LOCK_MUTEX(rb->Mutex);
att = _mesa_get_attachment(ctx, fb, attachment);
ASSERT(att);
-
if (rb) {
_mesa_set_renderbuffer_attachment(ctx, att, rb);
}
_mesa_remove_attachment(ctx, att);
}
- if (rb)
- _glthread_UNLOCK_MUTEX(rb->Mutex);
_glthread_UNLOCK_MUTEX(fb->Mutex);
}
/* OK */
}
else if (ctx->Extensions.EXT_packed_depth_stencil &&
- att->Renderbuffer->_BaseFormat == GL_DEPTH_STENCIL_EXT) {
+ texImage->TexFormat->BaseFormat == GL_DEPTH_STENCIL_EXT) {
/* OK */
}
else {
void GLAPIENTRY
_mesa_BindRenderbufferEXT(GLenum target, GLuint renderbuffer)
{
- struct gl_renderbuffer *newRb, *oldRb;
+ struct gl_renderbuffer *newRb;
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
}
FLUSH_VERTICES(ctx, _NEW_BUFFERS);
+ /* The above doesn't fully flush the drivers in the way that a
+ * glFlush does, but that is required here:
+ */
+ if (ctx->Driver.Flush)
+ ctx->Driver.Flush(ctx);
+
if (renderbuffer) {
newRb = _mesa_lookup_renderbuffer(ctx, renderbuffer);
}
ASSERT(newRb->AllocStorage);
_mesa_HashInsert(ctx->Shared->RenderBuffers, renderbuffer, newRb);
+ newRb->RefCount = 1; /* referenced by hash table */
}
- newRb->RefCount++;
}
else {
newRb = NULL;
}
- oldRb = ctx->CurrentRenderbuffer;
- if (oldRb) {
- oldRb->RefCount--;
- if (oldRb->RefCount == 0) {
- oldRb->Delete(oldRb);
- }
- }
-
ASSERT(newRb != &DummyRenderbuffer);
- ctx->CurrentRenderbuffer = newRb;
+ _mesa_reference_renderbuffer(&ctx->CurrentRenderbuffer, newRb);
}
_mesa_BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
}
- /* remove from hash table immediately, to free the ID */
+ /* Remove from hash table immediately, to free the ID.
+ * But the object will not be freed until it's no longer
+ * referenced anywhere else.
+ */
_mesa_HashRemove(ctx->Shared->RenderBuffers, renderbuffers[i]);
if (rb != &DummyRenderbuffer) {
- /* But the object will not be freed until it's no longer
- * bound in any context.
- */
- rb->RefCount--;
- if (rb->RefCount == 0) {
- rb->Delete(rb);
- }
+ /* no longer referenced by hash table */
+ _mesa_reference_renderbuffer(&rb, NULL);
}
}
}
GLuint i;
for (i = 0; i < BUFFER_COUNT; i++) {
struct gl_renderbuffer_attachment *att = fb->Attachment + i;
- struct gl_texture_object *texObj = att->Texture;
- if (texObj) {
+ if (att->Texture && att->Renderbuffer) {
ctx->Driver.FinishRenderTexture(ctx, att);
}
}
void GLAPIENTRY
_mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer)
{
- struct gl_framebuffer *newFb, *oldFb;
+ struct gl_framebuffer *newFb, *newFbread;
GLboolean bindReadBuf, bindDrawBuf;
GET_CURRENT_CONTEXT(ctx);
}
FLUSH_VERTICES(ctx, _NEW_BUFFERS);
-
+ if (ctx->Driver.Flush) {
+ ctx->Driver.Flush(ctx);
+ }
if (framebuffer) {
/* Binding a user-created framebuffer object */
newFb = _mesa_lookup_framebuffer(ctx, framebuffer);
}
_mesa_HashInsert(ctx->Shared->FrameBuffers, framebuffer, newFb);
}
- _glthread_LOCK_MUTEX(newFb->Mutex);
- if (bindReadBuf)
- newFb->RefCount++;
- if (bindDrawBuf)
- newFb->RefCount++;
- _glthread_UNLOCK_MUTEX(newFb->Mutex);
+ newFbread = newFb;
}
else {
/* Binding the window system framebuffer (which was originally set
* with MakeCurrent).
*/
newFb = ctx->WinSysDrawBuffer;
+ newFbread = ctx->WinSysReadBuffer;
}
ASSERT(newFb);
* XXX check if re-binding same buffer and skip some of this code.
*/
+ /* for window-framebuffers, re-initialize the fbo values, as they
+ could be wrong (makecurrent with a new drawable while still a fbo
+ was bound will lead to default init fbo values).
+ note that therefore the context ReadBuffer/DrawBuffer values are not
+ valid while fbo's are bound!!! */
if (bindReadBuf) {
- oldFb = ctx->ReadBuffer;
- if (oldFb && oldFb->Name != 0) {
- _glthread_LOCK_MUTEX(oldFb->Mutex);
- oldFb->RefCount--;
- _glthread_UNLOCK_MUTEX(oldFb->Mutex);
- if (oldFb->RefCount == 0) {
- oldFb->Delete(oldFb);
- }
+ _mesa_reference_framebuffer(&ctx->ReadBuffer, newFbread);
+ if (!newFbread->Name) {
+ _mesa_readbuffer_update_fields(ctx, ctx->Pixel.ReadBuffer);
}
- ctx->ReadBuffer = newFb;
}
if (bindDrawBuf) {
- oldFb = ctx->DrawBuffer;
- if (oldFb && oldFb->Name != 0) {
- /* check if old FB had any texture attachments */
- check_end_texture_render(ctx, oldFb);
- /* check if time to delete this framebuffer */
- _glthread_LOCK_MUTEX(oldFb->Mutex);
- oldFb->RefCount--;
- if (oldFb->RefCount == 0) {
- oldFb->Delete(oldFb);
+ /* check if old FB had any texture attachments */
+ check_end_texture_render(ctx, ctx->DrawBuffer);
+ /* check if time to delete this framebuffer */
+ _mesa_reference_framebuffer(&ctx->DrawBuffer, newFb);
+ if (!newFb->Name) {
+ GLuint i;
+ GLenum buffers[MAX_DRAW_BUFFERS];
+ for(i = 0; i < ctx->Const.MaxDrawBuffers; i++) {
+ buffers[i] = ctx->Color.DrawBuffer[i];
}
- _glthread_UNLOCK_MUTEX(oldFb->Mutex);
+ _mesa_drawbuffers(ctx, ctx->Const.MaxDrawBuffers, buffers, NULL);
}
- ctx->DrawBuffer = newFb;
- if (newFb->Name != 0) {
+ else {
/* check if newly bound framebuffer has any texture attachments */
check_begin_texture_render(ctx, newFb);
}
}
if (ctx->Driver.BindFramebuffer) {
- ctx->Driver.BindFramebuffer(ctx, target, newFb);
+ ctx->Driver.BindFramebuffer(ctx, target, newFb, newFbread);
}
}
ASSERT_OUTSIDE_BEGIN_END(ctx);
FLUSH_VERTICES(ctx, _NEW_BUFFERS);
+ /* The above doesn't fully flush the drivers in the way that a
+ * glFlush does, but that is required here:
+ */
+ if (ctx->Driver.Flush)
+ ctx->Driver.Flush(ctx);
for (i = 0; i < n; i++) {
if (framebuffers[i] > 0) {
/* But the object will not be freed until it's no longer
* bound in any context.
*/
- _glthread_LOCK_MUTEX(fb->Mutex);
- fb->RefCount--;
- _glthread_UNLOCK_MUTEX(fb->Mutex);
- if (fb->RefCount == 0) {
- fb->Delete(fb);
- }
+ _mesa_unreference_framebuffer(&fb);
}
}
}
* Common code called by glFramebufferTexture1D/2D/3DEXT().
*/
static void
-framebuffer_texture(GLuint dims, GLenum target, GLenum attachment,
- GLenum textarget, GLuint texture,
+framebuffer_texture(GLcontext *ctx, const char *caller, GLenum target,
+ GLenum attachment, GLenum textarget, GLuint texture,
GLint level, GLint zoffset)
{
struct gl_renderbuffer_attachment *att;
struct gl_texture_object *texObj = NULL;
struct gl_framebuffer *fb;
- GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
if (target != GL_FRAMEBUFFER_EXT) {
_mesa_error(ctx, GL_INVALID_ENUM,
- "glFramebufferTexture%dDEXT(target)", dims);
+ "glFramebufferTexture%sEXT(target)", caller);
return;
}
/* check framebuffer binding */
if (fb->Name == 0) {
_mesa_error(ctx, GL_INVALID_OPERATION,
- "glFramebufferTexture%dDEXT", dims);
+ "glFramebufferTexture%sEXT", caller);
return;
}
+
+ /* The textarget, level, and zoffset parameters are only validated if
+ * texture is non-zero.
+ */
if (texture) {
- texObj = _mesa_lookup_texture(ctx, texture);
- }
+ GLboolean err = GL_TRUE;
- /* Check dimension-dependent things */
- switch (dims) {
- case 1:
- if (textarget != GL_TEXTURE_1D) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glFramebufferTexture1DEXT(textarget)");
- return;
- }
- if (texObj && texObj->Target != GL_TEXTURE_1D) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glFramebufferTexture1DEXT(texture target mismatch)");
- return;
- }
- break;
- case 2:
- if (textarget != GL_TEXTURE_2D &&
- textarget != GL_TEXTURE_RECTANGLE_ARB &&
- !IS_CUBE_FACE(textarget)) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glFramebufferTexture2DEXT(textarget)");
- return;
- }
- if (texObj) {
- if ((texObj->Target == GL_TEXTURE_2D && textarget != GL_TEXTURE_2D) ||
- (texObj->Target == GL_TEXTURE_RECTANGLE_ARB
- && textarget != GL_TEXTURE_RECTANGLE_ARB) ||
- (texObj->Target == GL_TEXTURE_CUBE_MAP
- && !IS_CUBE_FACE(textarget))) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
- "glFramebufferTexture1DEXT(texture target mismatch)");
- return;
+ texObj = _mesa_lookup_texture(ctx, texture);
+ if (texObj != NULL) {
+ if (textarget == 0) {
+ err = (texObj->Target != GL_TEXTURE_3D) &&
+ (texObj->Target != GL_TEXTURE_1D_ARRAY_EXT) &&
+ (texObj->Target != GL_TEXTURE_2D_ARRAY_EXT);
+ }
+ else {
+ err = (texObj->Target == GL_TEXTURE_CUBE_MAP)
+ ? !IS_CUBE_FACE(textarget)
+ : (texObj->Target != textarget);
}
}
- break;
- case 3:
- if (textarget != GL_TEXTURE_3D) {
- _mesa_error(ctx, GL_INVALID_ENUM,
- "glFramebufferTexture3DEXT(textarget)");
- return;
- }
- if (texObj && texObj->Target != GL_TEXTURE_3D) {
+
+ if (err) {
_mesa_error(ctx, GL_INVALID_OPERATION,
- "glFramebufferTexture3DEXT(texture target mismatch)");
+ "glFramebufferTexture%sEXT(texture target mismatch)",
+ caller);
return;
}
- {
+
+ if (texObj->Target == GL_TEXTURE_3D) {
const GLint maxSize = 1 << (ctx->Const.Max3DTextureLevels - 1);
if (zoffset < 0 || zoffset >= maxSize) {
_mesa_error(ctx, GL_INVALID_VALUE,
- "glFramebufferTexture3DEXT(zoffset)");
+ "glFramebufferTexture%sEXT(zoffset)", caller);
+ return;
+ }
+ }
+ else if ((texObj->Target == GL_TEXTURE_1D_ARRAY_EXT) ||
+ (texObj->Target == GL_TEXTURE_2D_ARRAY_EXT)) {
+ if (zoffset < 0 || zoffset >= ctx->Const.MaxArrayTextureLayers) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glFramebufferTexture%sEXT(layer)", caller);
return;
}
}
- break;
- default:
- _mesa_problem(ctx, "Unexpected dims in error_check_framebuffer_texture");
- return;
- }
- if ((level < 0) || level >= _mesa_max_texture_levels(ctx, textarget)) {
- _mesa_error(ctx, GL_INVALID_VALUE,
- "glFramebufferTexture%dDEXT(level)", dims);
- return;
+
+ if ((level < 0) ||
+ (level >= _mesa_max_texture_levels(ctx, texObj->Target))) {
+ _mesa_error(ctx, GL_INVALID_VALUE,
+ "glFramebufferTexture%sEXT(level)", caller);
+ return;
+ }
}
att = _mesa_get_attachment(ctx, fb, attachment);
if (att == NULL) {
_mesa_error(ctx, GL_INVALID_ENUM,
- "glFramebufferTexture%dDEXT(attachment)", dims);
+ "glFramebufferTexture%sEXT(attachment)", caller);
return;
}
FLUSH_VERTICES(ctx, _NEW_BUFFERS);
+ /* The above doesn't fully flush the drivers in the way that a
+ * glFlush does, but that is required here:
+ */
+ if (ctx->Driver.Flush)
+ ctx->Driver.Flush(ctx);
_glthread_LOCK_MUTEX(fb->Mutex);
if (texObj) {
_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment,
GLenum textarget, GLuint texture, GLint level)
{
- const GLint zoffset = 0;
- framebuffer_texture(1, target, attachment, textarget, texture,
- level, zoffset);
+ GET_CURRENT_CONTEXT(ctx);
+
+ if ((texture != 0) && (textarget != GL_TEXTURE_1D)) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glFramebufferTexture1DEXT(textarget)");
+ return;
+ }
+
+ framebuffer_texture(ctx, "1D", target, attachment, textarget, texture,
+ level, 0);
}
_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment,
GLenum textarget, GLuint texture, GLint level)
{
- const GLint zoffset = 0;
- framebuffer_texture(2, target, attachment, textarget, texture,
- level, zoffset);
+ GET_CURRENT_CONTEXT(ctx);
+
+ if ((texture != 0) &&
+ (textarget != GL_TEXTURE_2D) &&
+ (textarget != GL_TEXTURE_RECTANGLE_ARB) &&
+ (!IS_CUBE_FACE(textarget))) {
+ _mesa_error(ctx, GL_INVALID_OPERATION,
+ "glFramebufferTexture2DEXT(textarget)");
+ return;
+ }
+
+ framebuffer_texture(ctx, "2D", target, attachment, textarget, texture,
+ level, 0);
}
GLenum textarget, GLuint texture,
GLint level, GLint zoffset)
{
- framebuffer_texture(3, target, attachment, textarget, texture,
+ GET_CURRENT_CONTEXT(ctx);
+
+ if ((texture != 0) && (textarget != GL_TEXTURE_3D)) {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glFramebufferTexture3DEXT(textarget)");
+ return;
+ }
+
+ framebuffer_texture(ctx, "3D", target, attachment, textarget, texture,
level, zoffset);
}
+void GLAPIENTRY
+_mesa_FramebufferTextureLayerEXT(GLenum target, GLenum attachment,
+ GLuint texture, GLint level, GLint layer)
+{
+ GET_CURRENT_CONTEXT(ctx);
+
+ framebuffer_texture(ctx, "Layer", target, attachment, 0, texture,
+ level, layer);
+}
+
void GLAPIENTRY
_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment,
}
FLUSH_VERTICES(ctx, _NEW_BUFFERS);
+ /* The above doesn't fully flush the drivers in the way that a
+ * glFlush does, but that is required here:
+ */
+ if (ctx->Driver.Flush)
+ ctx->Driver.Flush(ctx);
assert(ctx->Driver.FramebufferRenderbuffer);
ctx->Driver.FramebufferRenderbuffer(ctx, fb, attachment, rb);
}
FLUSH_VERTICES(ctx, _NEW_BUFFERS);
+ /* The above doesn't fully flush the drivers in the way that a
+ * glFlush does, but that is required here:
+ */
+ if (ctx->Driver.Flush)
+ ctx->Driver.Flush(ctx);
switch (pname) {
case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT:
texObj = _mesa_select_tex_object(ctx, texUnit, target);
/* XXX this might not handle cube maps correctly */
- _mesa_generate_mipmap(ctx, target, texUnit, texObj);
+ _mesa_lock_texture(ctx, texObj);
+ ctx->Driver.GenerateMipmap(ctx, target, texObj);
+ _mesa_unlock_texture(ctx, texObj);
}