diff options
Diffstat (limited to 'src/VBox/GuestHost/OpenGL/state_tracker/state_framebuffer.c')
| -rw-r--r-- | src/VBox/GuestHost/OpenGL/state_tracker/state_framebuffer.c | 620 |
1 files changed, 435 insertions, 185 deletions
diff --git a/src/VBox/GuestHost/OpenGL/state_tracker/state_framebuffer.c b/src/VBox/GuestHost/OpenGL/state_tracker/state_framebuffer.c index cdd3cecd..2f150361 100644 --- a/src/VBox/GuestHost/OpenGL/state_tracker/state_framebuffer.c +++ b/src/VBox/GuestHost/OpenGL/state_tracker/state_framebuffer.c @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2009 Oracle Corporation + * Copyright (C) 2009-2013 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; @@ -22,12 +22,6 @@ #include "state_internals.h" #include "cr_mem.h" -#define CRSTATE_FBO_CHECKERR(expr, result, message) \ - if (expr) { \ - crStateError(__LINE__, __FILE__, result, message); \ - return; \ - } - DECLEXPORT(void) STATE_APIENTRY crStateFramebufferObjectInit(CRContext *ctx) { @@ -39,6 +33,82 @@ crStateFramebufferObjectInit(CRContext *ctx) ctx->shared->bFBOResyncNeeded = GL_FALSE; } +void STATE_APIENTRY crStateGenFramebuffersEXT(GLsizei n, GLuint *buffers) +{ + CRContext *g = GetCurrentContext(); + crStateGenNames(g, g->shared->fbTable, n, buffers); +} + +void STATE_APIENTRY crStateGenRenderbuffersEXT(GLsizei n, GLuint *buffers) +{ + CRContext *g = GetCurrentContext(); + crStateGenNames(g, g->shared->rbTable, n, buffers); +} + +void crStateRegFramebuffers(GLsizei n, GLuint *buffers) +{ + CRContext *g = GetCurrentContext(); + crStateRegNames(g, g->shared->fbTable, n, buffers); +} + +void crStateRegRenderbuffers(GLsizei n, GLuint *buffers) +{ + CRContext *g = GetCurrentContext(); + crStateRegNames(g, g->shared->rbTable, n, buffers); +} + +static void crStateInitFrameBuffer(CRFramebufferObject *fbo); + +static CRFramebufferObject * +crStateFramebufferAllocate(CRContext *ctx, GLuint name) +{ + CRFramebufferObject *buffer = (CRFramebufferObject*) crCalloc(sizeof(CRFramebufferObject)); + CRSTATE_CHECKERR_RET(!buffer, GL_OUT_OF_MEMORY, "crStateFramebufferAllocate", NULL); + buffer->id = name; +#ifndef IN_GUEST + diff_api.GenFramebuffersEXT(1, &buffer->hwid); + if (!buffer->hwid) + { + crWarning("GenFramebuffersEXT failed!"); + crFree(buffer); + return NULL; + } +#else + buffer->hwid = name; +#endif + + crStateInitFrameBuffer(buffer); + crHashtableAdd(ctx->shared->fbTable, name, buffer); + CR_STATE_SHAREDOBJ_USAGE_INIT(buffer); + + return buffer; +} + +static CRRenderbufferObject * +crStateRenderbufferAllocate(CRContext *ctx, GLuint name) +{ + CRRenderbufferObject *buffer = (CRRenderbufferObject*) crCalloc(sizeof(CRRenderbufferObject)); + CRSTATE_CHECKERR_RET(!buffer, GL_OUT_OF_MEMORY, "crStateRenderbufferAllocate", NULL); + buffer->id = name; +#ifndef IN_GUEST + diff_api.GenRenderbuffersEXT(1, &buffer->hwid); + if (!buffer->hwid) + { + crWarning("GenRenderbuffersEXT failed!"); + crFree(buffer); + return NULL; + } +#else + buffer->hwid = name; +#endif + + buffer->internalformat = GL_RGBA; + crHashtableAdd(ctx->shared->rbTable, name, buffer); + CR_STATE_SHAREDOBJ_USAGE_INIT(buffer); + + return buffer; +} + void crStateFreeFBO(void *data) { CRFramebufferObject *pObj = (CRFramebufferObject *)data; @@ -83,28 +153,18 @@ crStateBindRenderbufferEXT(GLenum target, GLuint renderbuffer) CRContext *g = GetCurrentContext(); CRFramebufferObjectState *fbo = &g->framebufferobject; - CRSTATE_FBO_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); - CRSTATE_FBO_CHECKERR(target!=GL_RENDERBUFFER_EXT, GL_INVALID_ENUM, "invalid target"); + CRSTATE_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); + CRSTATE_CHECKERR(target!=GL_RENDERBUFFER_EXT, GL_INVALID_ENUM, "invalid target"); if (renderbuffer) { fbo->renderbuffer = (CRRenderbufferObject*) crHashtableSearch(g->shared->rbTable, renderbuffer); if (!fbo->renderbuffer) { - fbo->renderbuffer = (CRRenderbufferObject*) crCalloc(sizeof(CRRenderbufferObject)); - CRSTATE_FBO_CHECKERR(!fbo->renderbuffer, GL_OUT_OF_MEMORY, "glBindRenderbufferEXT"); - fbo->renderbuffer->id = renderbuffer; - fbo->renderbuffer->hwid = renderbuffer; - fbo->renderbuffer->internalformat = GL_RGBA; - crHashtableAdd(g->shared->rbTable, renderbuffer, fbo->renderbuffer); -#ifndef IN_GUEST - CR_STATE_SHAREDOBJ_USAGE_INIT(fbo->renderbuffer); -#endif + CRSTATE_CHECKERR(!crHashtableIsKeyUsed(g->shared->rbTable, renderbuffer), GL_INVALID_OPERATION, "name is not a renderbuffer"); + fbo->renderbuffer = crStateRenderbufferAllocate(g, renderbuffer); } -#ifndef IN_GUEST CR_STATE_SHAREDOBJ_USAGE_SET(fbo->renderbuffer, g); -#endif - } else fbo->renderbuffer = NULL; } @@ -147,6 +207,22 @@ static void crStateCheckFBOAttachments(CRFramebufferObject *pFBO, GLuint rbo, GL } } +static void ctStateRenderbufferRefsCleanup(CRContext *g, GLuint fboId, CRRenderbufferObject *rbo) +{ + CRFramebufferObjectState *fbo = &g->framebufferobject; + + if (fbo->renderbuffer==rbo) + { + fbo->renderbuffer = NULL; + } + + /* check the attachments of current framebuffers */ + crStateCheckFBOAttachments(fbo->readFB, fboId, GL_READ_FRAMEBUFFER); + crStateCheckFBOAttachments(fbo->drawFB, fboId, GL_DRAW_FRAMEBUFFER); + + CR_STATE_SHAREDOBJ_USAGE_CLEAR(rbo, g); +} + DECLEXPORT(void) STATE_APIENTRY crStateDeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers) { @@ -154,8 +230,8 @@ crStateDeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers) CRFramebufferObjectState *fbo = &g->framebufferobject; int i; - CRSTATE_FBO_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); - CRSTATE_FBO_CHECKERR(n<0, GL_INVALID_OPERATION, "n<0"); + CRSTATE_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); + CRSTATE_CHECKERR(n<0, GL_INVALID_OPERATION, "n<0"); for (i = 0; i < n; i++) { @@ -165,15 +241,29 @@ crStateDeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers) rbo = (CRRenderbufferObject*) crHashtableSearch(g->shared->rbTable, renderbuffers[i]); if (rbo) { - if (fbo->renderbuffer==rbo) + int j; + + ctStateRenderbufferRefsCleanup(g, renderbuffers[i], rbo); + CR_STATE_SHAREDOBJ_USAGE_FOREACH_USED_IDX(rbo, j) { - fbo->renderbuffer = NULL; + /* saved state version <= SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS does not have usage bits info, + * so on restore, we set mark bits as used. + * This is why g_pAvailableContexts[j] could be NULL + * also g_pAvailableContexts[0] will hold default context, which we should discard */ + CRContext *ctx = g_pAvailableContexts[j]; + if (j && ctx) + { + CRFramebufferObjectState *ctxFbo; + CRASSERT(ctx); + ctxFbo = &ctx->framebufferobject; + if (ctxFbo->renderbuffer==rbo) + crWarning("deleting RBO being used by another context %d", ctx->id); + + ctStateRenderbufferRefsCleanup(ctx, renderbuffers[i], rbo); + } + else + CR_STATE_SHAREDOBJ_USAGE_CLEAR_IDX(rbo, j); } - - /* check the attachments of current framebuffers */ - crStateCheckFBOAttachments(fbo->readFB, renderbuffers[i], GL_READ_FRAMEBUFFER); - crStateCheckFBOAttachments(fbo->drawFB, renderbuffers[i], GL_DRAW_FRAMEBUFFER); - crHashtableDelete(g->shared->rbTable, renderbuffers[i], crStateFreeRBO); } } @@ -187,9 +277,9 @@ crStateRenderbufferStorageEXT(GLenum target, GLenum internalformat, GLsizei widt CRFramebufferObjectState *fbo = &g->framebufferobject; CRRenderbufferObject *rb = fbo->renderbuffer; - CRSTATE_FBO_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); - CRSTATE_FBO_CHECKERR(target!=GL_RENDERBUFFER_EXT, GL_INVALID_ENUM, "invalid target"); - CRSTATE_FBO_CHECKERR(!rb, GL_INVALID_OPERATION, "no bound renderbuffer"); + CRSTATE_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); + CRSTATE_CHECKERR(target!=GL_RENDERBUFFER_EXT, GL_INVALID_ENUM, "invalid target"); + CRSTATE_CHECKERR(!rb, GL_INVALID_OPERATION, "no bound renderbuffer"); rb->width = width; rb->height = height; @@ -203,9 +293,9 @@ crStateGetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params) CRFramebufferObjectState *fbo = &g->framebufferobject; CRRenderbufferObject *rb = fbo->renderbuffer; - CRSTATE_FBO_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); - CRSTATE_FBO_CHECKERR(target!=GL_RENDERBUFFER_EXT, GL_INVALID_ENUM, "invalid target"); - CRSTATE_FBO_CHECKERR(!rb, GL_INVALID_OPERATION, "no bound renderbuffer"); + CRSTATE_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); + CRSTATE_CHECKERR(target!=GL_RENDERBUFFER_EXT, GL_INVALID_ENUM, "invalid target"); + CRSTATE_CHECKERR(!rb, GL_INVALID_OPERATION, "no bound renderbuffer"); switch (pname) { @@ -224,10 +314,10 @@ crStateGetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params) case GL_RENDERBUFFER_ALPHA_SIZE_EXT: case GL_RENDERBUFFER_DEPTH_SIZE_EXT: case GL_RENDERBUFFER_STENCIL_SIZE_EXT: - CRSTATE_FBO_CHECKERR(GL_TRUE, GL_INVALID_OPERATION, "unimplemented"); + CRSTATE_CHECKERR(GL_TRUE, GL_INVALID_OPERATION, "unimplemented"); break; default: - CRSTATE_FBO_CHECKERR(GL_TRUE, GL_INVALID_ENUM, "invalid pname"); + CRSTATE_CHECKERR(GL_TRUE, GL_INVALID_ENUM, "invalid pname"); } } @@ -286,8 +376,8 @@ crStateBindFramebufferEXT(GLenum target, GLuint framebuffer) CRFramebufferObjectState *fbo = &g->framebufferobject; CRFramebufferObject *pFBO=NULL; - CRSTATE_FBO_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); - CRSTATE_FBO_CHECKERR(((target!=GL_FRAMEBUFFER_EXT) && (target!=GL_READ_FRAMEBUFFER) && (target!=GL_DRAW_FRAMEBUFFER)), + CRSTATE_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); + CRSTATE_CHECKERR(((target!=GL_FRAMEBUFFER_EXT) && (target!=GL_READ_FRAMEBUFFER) && (target!=GL_DRAW_FRAMEBUFFER)), GL_INVALID_ENUM, "invalid target"); if (framebuffer) @@ -295,20 +385,12 @@ crStateBindFramebufferEXT(GLenum target, GLuint framebuffer) pFBO = (CRFramebufferObject*) crHashtableSearch(g->shared->fbTable, framebuffer); if (!pFBO) { - pFBO = (CRFramebufferObject*) crCalloc(sizeof(CRFramebufferObject)); - CRSTATE_FBO_CHECKERR(!pFBO, GL_OUT_OF_MEMORY, "glBindFramebufferEXT"); - pFBO->id = framebuffer; - pFBO->hwid = framebuffer; - crStateInitFrameBuffer(pFBO); - crHashtableAdd(g->shared->fbTable, framebuffer, pFBO); -#ifndef IN_GUEST - CR_STATE_SHAREDOBJ_USAGE_INIT(pFBO); -#endif + CRSTATE_CHECKERR(!crHashtableIsKeyUsed(g->shared->fbTable, framebuffer), GL_INVALID_OPERATION, "name is not a framebuffer"); + pFBO = crStateFramebufferAllocate(g, framebuffer); } -#ifndef IN_GUEST + CR_STATE_SHAREDOBJ_USAGE_SET(pFBO, g); -#endif } /* @todo: http://www.opengl.org/registry/specs/ARB/framebuffer_object.txt @@ -331,15 +413,29 @@ crStateBindFramebufferEXT(GLenum target, GLuint framebuffer) } } +static void ctStateFramebufferRefsCleanup(CRContext *g, CRFramebufferObject *fb) +{ + CRFramebufferObjectState *fbo = &g->framebufferobject; + if (fbo->readFB==fb) + { + fbo->readFB = NULL; + } + if (fbo->drawFB==fb) + { + fbo->drawFB = NULL; + } + + CR_STATE_SHAREDOBJ_USAGE_CLEAR(fb, g); +} + DECLEXPORT(void) STATE_APIENTRY crStateDeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers) { CRContext *g = GetCurrentContext(); - CRFramebufferObjectState *fbo = &g->framebufferobject; int i; - CRSTATE_FBO_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); - CRSTATE_FBO_CHECKERR(n<0, GL_INVALID_OPERATION, "n<0"); + CRSTATE_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); + CRSTATE_CHECKERR(n<0, GL_INVALID_OPERATION, "n<0"); for (i = 0; i < n; i++) { @@ -349,13 +445,32 @@ crStateDeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers) fb = (CRFramebufferObject*) crHashtableSearch(g->shared->fbTable, framebuffers[i]); if (fb) { - if (fbo->readFB==fb) - { - fbo->readFB = NULL; - } - if (fbo->drawFB==fb) + int j; + + ctStateFramebufferRefsCleanup(g, fb); + + CR_STATE_SHAREDOBJ_USAGE_FOREACH_USED_IDX(fb, j) { - fbo->drawFB = NULL; + /* saved state version <= SHCROGL_SSM_VERSION_BEFORE_CTXUSAGE_BITS does not have usage bits info, + * so on restore, we set mark bits as used. + * This is why g_pAvailableContexts[j] could be NULL + * also g_pAvailableContexts[0] will hold default context, which we should discard */ + CRContext *ctx = g_pAvailableContexts[j]; + if (j && ctx) + { + CRFramebufferObjectState *ctxFbo; + CRASSERT(ctx); + ctxFbo = &ctx->framebufferobject; + if (ctxFbo->readFB==fb) + crWarning("deleting FBO being used as read buffer by another context %d", ctx->id); + + if (ctxFbo->drawFB==fb) + crWarning("deleting FBO being used as draw buffer by another context %d", ctx->id); + + ctStateFramebufferRefsCleanup(ctx, fb); + } + else + CR_STATE_SHAREDOBJ_USAGE_CLEAR_IDX(fb, j); } crHashtableDelete(g->shared->fbTable, framebuffers[i], crStateFreeFBO); } @@ -380,27 +495,72 @@ unsigned int crLog2Floor(unsigned int x) return (x & 0x0000003f) - 1; } -static void crStateFramebufferTextureCheck(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, - GLboolean *failed, CRFBOAttachmentPoint **ap, CRTextureObj **tobj) +static GLuint crStateFramebufferGet(CRFramebufferObjectState *fbo, GLenum target, CRFramebufferObject **apFBOs) +{ + GLuint cPBOs = 0; + switch (target) + { + case GL_READ_FRAMEBUFFER: + cPBOs = 1; + apFBOs[0] = fbo->readFB; + break; + case GL_DRAW_FRAMEBUFFER: + cPBOs = 1; + apFBOs[0] = fbo->drawFB; + break; + case GL_FRAMEBUFFER: + if (fbo->readFB == fbo->drawFB) + { + cPBOs = 1; + apFBOs[0] = fbo->readFB; + } + else + { + cPBOs = 2; + apFBOs[0] = fbo->readFB; + apFBOs[1] = fbo->drawFB; + } + break; + default: + crWarning("unexpected target value: 0x%x", target); + cPBOs = 0; + break; + } + + return cPBOs; +} + +static GLuint crStateFramebufferTextureCheck(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, + CRFBOAttachmentPoint **aap, CRTextureObj **tobj) { CRContext *g = GetCurrentContext(); CRFramebufferObjectState *fbo = &g->framebufferobject; - CRFramebufferObject *pFBO; + CRFramebufferObject *apFBOs[2]; + GLuint cFBOs = 0, i; GLuint maxtexsizelog2; - *failed = GL_TRUE; + CRSTATE_CHECKERR_RET(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end", 0); + CRSTATE_CHECKERR_RET(((target!=GL_FRAMEBUFFER_EXT) && (target!=GL_READ_FRAMEBUFFER) && (target!=GL_DRAW_FRAMEBUFFER)), + GL_INVALID_ENUM, "invalid target", 0); - CRSTATE_FBO_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); - CRSTATE_FBO_CHECKERR(((target!=GL_FRAMEBUFFER_EXT) && (target!=GL_READ_FRAMEBUFFER) && (target!=GL_DRAW_FRAMEBUFFER)), - GL_INVALID_ENUM, "invalid target"); - pFBO = GL_READ_FRAMEBUFFER==target ? fbo->readFB : fbo->drawFB; - CRSTATE_FBO_CHECKERR(!pFBO, GL_INVALID_OPERATION, "no fbo bound"); - CRSTATE_FBO_CHECKERR(!crStateGetFBOAttachmentPoint(pFBO, attachment, ap), GL_INVALID_ENUM, "invalid attachment"); + cFBOs = crStateFramebufferGet(fbo, target, apFBOs); + CRSTATE_CHECKERR_RET(!cFBOs, GL_INVALID_ENUM, "unexpected target", 0); + for (i = 0; i < cFBOs; ++i) + { + CRSTATE_CHECKERR_RET(!apFBOs[i], GL_INVALID_OPERATION, "zero fbo bound", 0); + } + + Assert(cFBOs); + Assert(cFBOs <= 2); + + for (i = 0; i < cFBOs; ++i) + { + CRSTATE_CHECKERR_RET(!crStateGetFBOAttachmentPoint(apFBOs[i], attachment, &aap[i]), GL_INVALID_ENUM, "invalid attachment", 0); + } if (!texture) { - *failed = GL_FALSE; - return; + return cFBOs; } switch (textarget) @@ -428,27 +588,33 @@ static void crStateFramebufferTextureCheck(GLenum target, GLenum attachment, GLe *tobj = crStateTextureGet(textarget, texture); break; default: - CRSTATE_FBO_CHECKERR(GL_TRUE, GL_INVALID_OPERATION, "invalid textarget"); + CRSTATE_CHECKERR_RET(GL_TRUE, GL_INVALID_OPERATION, "invalid textarget", 0); } - CRSTATE_FBO_CHECKERR(!*tobj, GL_INVALID_OPERATION, "invalid textarget/texture combo"); + CRSTATE_CHECKERR_RET(!*tobj, GL_INVALID_OPERATION, "invalid textarget/texture combo", 0); if (GL_TEXTURE_RECTANGLE_ARB==textarget) { - CRSTATE_FBO_CHECKERR(level!=0, GL_INVALID_VALUE, "non zero mipmap level"); + CRSTATE_CHECKERR_RET(level!=0, GL_INVALID_VALUE, "non zero mipmap level", 0); } - CRSTATE_FBO_CHECKERR(level<0, GL_INVALID_VALUE, "level<0"); - CRSTATE_FBO_CHECKERR(level>maxtexsizelog2, GL_INVALID_VALUE, "level too big"); - - *failed = GL_FALSE; + CRSTATE_CHECKERR_RET(level<0, GL_INVALID_VALUE, "level<0", 0); + CRSTATE_CHECKERR_RET(level>maxtexsizelog2, GL_INVALID_VALUE, "level too big", 0); #ifdef IN_GUEST - if ((*ap)->type!=GL_TEXTURE || (*ap)->name!=texture || (*ap)->level!=level) + for (i = 0; i < cFBOs; ++i) { - pFBO->status = GL_FRAMEBUFFER_UNDEFINED; + if ((aap[i])->type!=GL_TEXTURE || (aap[i])->name!=texture || (aap[i])->level!=level) + { + apFBOs[i]->status = GL_FRAMEBUFFER_UNDEFINED; + } } #endif + + Assert(cFBOs); + Assert(cFBOs <= 2); + + return cFBOs; } DECLEXPORT(void) STATE_APIENTRY @@ -456,29 +622,33 @@ crStateFramebufferTexture1DEXT(GLenum target, GLenum attachment, GLenum textarge { CRContext *g = GetCurrentContext(); CRFramebufferObjectState *fbo = &g->framebufferobject; - CRFBOAttachmentPoint *ap; + CRFBOAttachmentPoint *aap[2]; + GLuint cap, i; CRTextureObj *tobj; - GLboolean failed; - crStateFramebufferTextureCheck(target, attachment, textarget, texture, level, &failed, &ap, &tobj); - if (failed) return; + cap = crStateFramebufferTextureCheck(target, attachment, textarget, texture, level, aap, &tobj); + if (!cap) return; if (!texture) { - crStateInitFBOAttachmentPoint(ap); + for (i = 0; i < cap; ++i) + { + crStateInitFBOAttachmentPoint(aap[i]); + } return; } - CRSTATE_FBO_CHECKERR(textarget!=GL_TEXTURE_1D, GL_INVALID_OPERATION, "textarget"); + CRSTATE_CHECKERR(textarget!=GL_TEXTURE_1D, GL_INVALID_OPERATION, "textarget"); -#ifndef IN_GUEST CR_STATE_SHAREDOBJ_USAGE_SET(tobj, g); -#endif - crStateInitFBOAttachmentPoint(ap); - ap->type = GL_TEXTURE; - ap->name = texture; - ap->level = level; + for (i = 0; i < cap; ++i) + { + crStateInitFBOAttachmentPoint(aap[i]); + aap[i]->type = GL_TEXTURE; + aap[i]->name = texture; + aap[i]->level = level; + } } DECLEXPORT(void) STATE_APIENTRY @@ -486,32 +656,36 @@ crStateFramebufferTexture2DEXT(GLenum target, GLenum attachment, GLenum textarge { CRContext *g = GetCurrentContext(); CRFramebufferObjectState *fbo = &g->framebufferobject; - CRFBOAttachmentPoint *ap; + CRFBOAttachmentPoint *aap[2]; + GLuint cap, i; CRTextureObj *tobj; - GLboolean failed; - crStateFramebufferTextureCheck(target, attachment, textarget, texture, level, &failed, &ap, &tobj); - if (failed) return; + cap = crStateFramebufferTextureCheck(target, attachment, textarget, texture, level, aap, &tobj); + if (!cap) return; if (!texture) { - crStateInitFBOAttachmentPoint(ap); + for (i = 0; i < cap; ++i) + { + crStateInitFBOAttachmentPoint(aap[i]); + } return; } - CRSTATE_FBO_CHECKERR(GL_TEXTURE_1D==textarget || GL_TEXTURE_3D==textarget, GL_INVALID_OPERATION, "textarget"); + CRSTATE_CHECKERR(GL_TEXTURE_1D==textarget || GL_TEXTURE_3D==textarget, GL_INVALID_OPERATION, "textarget"); -#ifndef IN_GUEST CR_STATE_SHAREDOBJ_USAGE_SET(tobj, g); -#endif - crStateInitFBOAttachmentPoint(ap); - ap->type = GL_TEXTURE; - ap->name = texture; - ap->level = level; - if (textarget!=GL_TEXTURE_2D && textarget!=GL_TEXTURE_RECTANGLE_ARB) + for (i = 0; i < cap; ++i) { - ap->face = textarget; + crStateInitFBOAttachmentPoint(aap[i]); + aap[i]->type = GL_TEXTURE; + aap[i]->name = texture; + aap[i]->level = level; + if (textarget!=GL_TEXTURE_2D && textarget!=GL_TEXTURE_RECTANGLE_ARB) + { + aap[i]->face = textarget; + } } } @@ -520,31 +694,35 @@ crStateFramebufferTexture3DEXT(GLenum target, GLenum attachment, GLenum textarge { CRContext *g = GetCurrentContext(); CRFramebufferObjectState *fbo = &g->framebufferobject; - CRFBOAttachmentPoint *ap; + CRFBOAttachmentPoint *aap[2]; + GLuint cap, i; CRTextureObj *tobj; - GLboolean failed; - crStateFramebufferTextureCheck(target, attachment, textarget, texture, level, &failed, &ap, &tobj); - if (failed) return; + cap = crStateFramebufferTextureCheck(target, attachment, textarget, texture, level, aap, &tobj); + if (!cap) return; if (!texture) { - crStateInitFBOAttachmentPoint(ap); + for (i = 0; i < cap; ++i) + { + crStateInitFBOAttachmentPoint(aap[i]); + } return; } - CRSTATE_FBO_CHECKERR(zoffset>(g->limits.max3DTextureSize-1), GL_INVALID_VALUE, "zoffset too big"); - CRSTATE_FBO_CHECKERR(textarget!=GL_TEXTURE_3D, GL_INVALID_OPERATION, "textarget"); + CRSTATE_CHECKERR(zoffset>(g->limits.max3DTextureSize-1), GL_INVALID_VALUE, "zoffset too big"); + CRSTATE_CHECKERR(textarget!=GL_TEXTURE_3D, GL_INVALID_OPERATION, "textarget"); -#ifndef IN_GUEST CR_STATE_SHAREDOBJ_USAGE_SET(tobj, g); -#endif - crStateInitFBOAttachmentPoint(ap); - ap->type = GL_TEXTURE; - ap->name = texture; - ap->level = level; - ap->zoffset = zoffset; + for (i = 0; i < cap; ++i) + { + crStateInitFBOAttachmentPoint(aap[i]); + aap[i]->type = GL_TEXTURE; + aap[i]->name = texture; + aap[i]->level = level; + aap[i]->zoffset = zoffset; + } } DECLEXPORT(void) STATE_APIENTRY @@ -552,41 +730,62 @@ crStateFramebufferRenderbufferEXT(GLenum target, GLenum attachment, GLenum rende { CRContext *g = GetCurrentContext(); CRFramebufferObjectState *fbo = &g->framebufferobject; - CRFramebufferObject *pFBO; - CRFBOAttachmentPoint *ap; + CRFramebufferObject *apFBOs[2]; + GLuint cFBOs, i; + CRFBOAttachmentPoint *aap[2]; CRRenderbufferObject *rb; - CRSTATE_FBO_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); - CRSTATE_FBO_CHECKERR(((target!=GL_FRAMEBUFFER_EXT) && (target!=GL_READ_FRAMEBUFFER) && (target!=GL_DRAW_FRAMEBUFFER)), + CRSTATE_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); + CRSTATE_CHECKERR(((target!=GL_FRAMEBUFFER_EXT) && (target!=GL_READ_FRAMEBUFFER) && (target!=GL_DRAW_FRAMEBUFFER)), GL_INVALID_ENUM, "invalid target"); - pFBO = GL_READ_FRAMEBUFFER==target ? fbo->readFB : fbo->drawFB; - CRSTATE_FBO_CHECKERR(!pFBO, GL_INVALID_OPERATION, "no fbo bound"); - CRSTATE_FBO_CHECKERR(!crStateGetFBOAttachmentPoint(pFBO, attachment, &ap), GL_INVALID_ENUM, "invalid attachment"); + cFBOs = crStateFramebufferGet(fbo, target, apFBOs); + CRSTATE_CHECKERR(!cFBOs, GL_INVALID_OPERATION, "no fbo bound"); + for (i = 0; i < cFBOs; ++i) + { + CRSTATE_CHECKERR(!apFBOs[i], GL_INVALID_OPERATION, "zero fbo bound"); + } + + for (i = 0; i < cFBOs; ++i) + { + CRSTATE_CHECKERR(!crStateGetFBOAttachmentPoint(apFBOs[i], attachment, &aap[i]), GL_INVALID_ENUM, "invalid attachment"); + } if (!renderbuffer) { -#ifdef IN_GUEST - if (ap->type!=GL_NONE) + for (i = 0; i < cFBOs; ++i) { - pFBO->status = GL_FRAMEBUFFER_UNDEFINED; - } +#ifdef IN_GUEST + if (&aap[i]->type!=GL_NONE) + { + apFBOs[i]->status = GL_FRAMEBUFFER_UNDEFINED; + } #endif - crStateInitFBOAttachmentPoint(ap); + crStateInitFBOAttachmentPoint(aap[i]); + } return; } rb = (CRRenderbufferObject*) crHashtableSearch(g->shared->rbTable, renderbuffer); - CRSTATE_FBO_CHECKERR(!rb, GL_INVALID_OPERATION, "rb doesn't exist"); + if (!rb) + { + CRSTATE_CHECKERR(!crHashtableIsKeyUsed(g->shared->rbTable, renderbuffer), GL_INVALID_OPERATION, "rb doesn't exist"); + rb = crStateRenderbufferAllocate(g, renderbuffer); + } + CR_STATE_SHAREDOBJ_USAGE_SET(rb, g); + + for (i = 0; i < cFBOs; ++i) + { #ifdef IN_GUEST - if (ap->type!=GL_RENDERBUFFER_EXT || ap->name!=renderbuffer) + if (aap[i]->type!=GL_RENDERBUFFER_EXT || aap[i]->name!=renderbuffer) { - pFBO->status = GL_FRAMEBUFFER_UNDEFINED; + apFBOs[i]->status = GL_FRAMEBUFFER_UNDEFINED; } #endif - crStateInitFBOAttachmentPoint(ap); - ap->type = GL_RENDERBUFFER_EXT; - ap->name = renderbuffer; + crStateInitFBOAttachmentPoint(aap[i]); + aap[i]->type = GL_RENDERBUFFER_EXT; + aap[i]->name = renderbuffer; + } } DECLEXPORT(void) STATE_APIENTRY @@ -594,40 +793,87 @@ crStateGetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, { CRContext *g = GetCurrentContext(); CRFramebufferObjectState *fbo = &g->framebufferobject; - CRFramebufferObject *pFBO; + CRFramebufferObject *apFBOs[2]; + GLint cFBOs = 0, i; CRFBOAttachmentPoint *ap; - CRSTATE_FBO_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); - CRSTATE_FBO_CHECKERR(((target!=GL_FRAMEBUFFER_EXT) && (target!=GL_READ_FRAMEBUFFER) && (target!=GL_DRAW_FRAMEBUFFER)), + CRSTATE_CHECKERR(g->current.inBeginEnd, GL_INVALID_OPERATION, "called in begin/end"); + CRSTATE_CHECKERR(((target!=GL_FRAMEBUFFER_EXT) && (target!=GL_READ_FRAMEBUFFER) && (target!=GL_DRAW_FRAMEBUFFER)), GL_INVALID_ENUM, "invalid target"); - pFBO = GL_READ_FRAMEBUFFER==target ? fbo->readFB : fbo->drawFB; - CRSTATE_FBO_CHECKERR(!pFBO, GL_INVALID_OPERATION, "no fbo bound"); - CRSTATE_FBO_CHECKERR(!crStateGetFBOAttachmentPoint(pFBO, attachment, &ap), GL_INVALID_ENUM, "invalid attachment"); - switch (pname) + cFBOs = crStateFramebufferGet(fbo, target, apFBOs); + + CRSTATE_CHECKERR(!cFBOs, GL_INVALID_OPERATION, "no fbo bound"); + for (i = 0; i < cFBOs; ++i) { - case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: - *params = ap->type; - break; - case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: - CRSTATE_FBO_CHECKERR(ap->type!=GL_RENDERBUFFER_EXT && ap->type!=GL_TEXTURE, GL_INVALID_ENUM, "can't query object name when it's not bound") - *params = ap->name; - break; - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT: - CRSTATE_FBO_CHECKERR(ap->type!=GL_TEXTURE, GL_INVALID_ENUM, "not a texture"); - *params = ap->level; - break; - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT: - CRSTATE_FBO_CHECKERR(ap->type!=GL_TEXTURE, GL_INVALID_ENUM, "not a texture"); - *params = ap->face; - break; - case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT: - CRSTATE_FBO_CHECKERR(ap->type!=GL_TEXTURE, GL_INVALID_ENUM, "not a texture"); - *params = ap->zoffset; - break; - default: - CRSTATE_FBO_CHECKERR(GL_TRUE, GL_INVALID_ENUM, "invalid pname"); + CRSTATE_CHECKERR(!apFBOs[i], GL_INVALID_OPERATION, "zero fbo bound"); + } + + if(cFBOs != 1) + { + crWarning("different FBPs attached to draw and read buffers, returning info for the read buffer"); + } + + for (i = 0; i < 1; ++i) + { + CRSTATE_CHECKERR(!crStateGetFBOAttachmentPoint(apFBOs[i], attachment, &ap), GL_INVALID_ENUM, "invalid attachment"); + + switch (pname) + { + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT: + *params = ap->type; + break; + case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT: + CRSTATE_CHECKERR(ap->type!=GL_RENDERBUFFER_EXT && ap->type!=GL_TEXTURE, GL_INVALID_ENUM, "can't query object name when it's not bound") + *params = ap->name; + break; + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT: + CRSTATE_CHECKERR(ap->type!=GL_TEXTURE, GL_INVALID_ENUM, "not a texture"); + *params = ap->level; + break; + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_EXT: + CRSTATE_CHECKERR(ap->type!=GL_TEXTURE, GL_INVALID_ENUM, "not a texture"); + *params = ap->face; + break; + case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_EXT: + CRSTATE_CHECKERR(ap->type!=GL_TEXTURE, GL_INVALID_ENUM, "not a texture"); + *params = ap->zoffset; + break; + default: + CRSTATE_CHECKERR(GL_TRUE, GL_INVALID_ENUM, "invalid pname"); + } + } +} + +DECLEXPORT(GLboolean) STATE_APIENTRY crStateIsFramebufferEXT( GLuint framebuffer ) +{ + CRContext *g = GetCurrentContext(); + + FLUSH(); + + if (g->current.inBeginEnd) { + crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, + "glIsFramebufferEXT called in begin/end"); + return GL_FALSE; } + + return framebuffer ? crHashtableIsKeyUsed(g->shared->fbTable, framebuffer) : GL_FALSE; +} + +DECLEXPORT(GLboolean) STATE_APIENTRY crStateIsRenderbufferEXT( GLuint renderbuffer ) +{ + CRContext *g = GetCurrentContext(); + + + FLUSH(); + + if (g->current.inBeginEnd) { + crStateError(__LINE__, __FILE__, GL_INVALID_OPERATION, + "glIsRenderbufferEXT called in begin/end"); + return GL_FALSE; + } + + return renderbuffer ? crHashtableIsKeyUsed(g->shared->rbTable, renderbuffer) : GL_FALSE; } DECLEXPORT(void) STATE_APIENTRY @@ -642,8 +888,11 @@ static void crStateSyncRenderbuffersCB(unsigned long key, void *data1, void *dat diff_api.GenRenderbuffersEXT(1, &pRBO->hwid); - diff_api.BindRenderbufferEXT(GL_RENDERBUFFER_EXT, pRBO->hwid); - diff_api.RenderbufferStorageEXT(GL_RENDERBUFFER_EXT, pRBO->internalformat, pRBO->width, pRBO->height); + if (pRBO->width && pRBO->height) + { + diff_api.BindRenderbufferEXT(GL_RENDERBUFFER_EXT, pRBO->hwid); + diff_api.RenderbufferStorageEXT(GL_RENDERBUFFER_EXT, pRBO->internalformat, pRBO->width, pRBO->height); + } } static void crStateSyncAP(CRFBOAttachmentPoint *pAP, GLenum ap, CRContext *ctx) @@ -774,36 +1023,37 @@ crStateFramebufferObjectSwitch(CRContext *from, CRContext *to) } DECLEXPORT(void) STATE_APIENTRY -crStateFramebufferObjectDisableHW(CRContext *ctx, GLuint idFBO) +crStateFramebufferObjectDisableHW(CRContext *ctx, GLuint idDrawFBO, GLuint idReadFBO) { - GLboolean fAdjustDrawReadBuffers = GL_FALSE; + GLenum idDrawBuffer = 0, idReadBuffer = 0; - if (ctx->framebufferobject.drawFB || idFBO) + if (ctx->framebufferobject.drawFB || idDrawFBO) { diff_api.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0); - fAdjustDrawReadBuffers = GL_TRUE; + idDrawBuffer = ctx->buffer.drawBuffer; } - if (ctx->framebufferobject.readFB ||idFBO) + if (ctx->framebufferobject.readFB || idReadFBO) { diff_api.BindFramebufferEXT(GL_READ_FRAMEBUFFER, 0); - fAdjustDrawReadBuffers = GL_TRUE; + idReadBuffer = ctx->buffer.readBuffer; } - if (fAdjustDrawReadBuffers) - { - diff_api.DrawBuffer(GL_BACK); - diff_api.ReadBuffer(GL_BACK); - } + if (idDrawBuffer) + diff_api.DrawBuffer(idDrawBuffer); + if (idReadBuffer) + diff_api.ReadBuffer(idReadBuffer); if (ctx->framebufferobject.renderbuffer) diff_api.BindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0); } DECLEXPORT(void) STATE_APIENTRY -crStateFramebufferObjectReenableHW(CRContext *fromCtx, CRContext *toCtx, GLuint idFBO) +crStateFramebufferObjectReenableHW(CRContext *fromCtx, CRContext *toCtx, GLuint idDrawFBO, GLuint idReadFBO) { GLuint idReadBuffer = 0, idDrawBuffer = 0; + if (!fromCtx) + fromCtx = toCtx; /* <- in case fromCtx is zero, set it to toCtx to ensure framebuffer state gets re-enabled correctly */ if ((fromCtx->framebufferobject.drawFB) /* <- the FBO state was reset in crStateFramebufferObjectDisableHW */ && fromCtx->framebufferobject.drawFB == toCtx->framebufferobject.drawFB) /* .. and it was NOT restored properly in crStateFramebufferObjectSwitch */ @@ -811,9 +1061,9 @@ crStateFramebufferObjectReenableHW(CRContext *fromCtx, CRContext *toCtx, GLuint diff_api.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, toCtx->framebufferobject.drawFB->hwid); idDrawBuffer = toCtx->framebufferobject.drawFB->drawbuffer[0]; } - else if (idFBO && !toCtx->framebufferobject.drawFB) + else if (idDrawFBO && !toCtx->framebufferobject.drawFB) { - diff_api.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, idFBO); + diff_api.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, idDrawFBO); idDrawBuffer = GL_COLOR_ATTACHMENT0; } @@ -823,9 +1073,9 @@ crStateFramebufferObjectReenableHW(CRContext *fromCtx, CRContext *toCtx, GLuint diff_api.BindFramebufferEXT(GL_READ_FRAMEBUFFER, toCtx->framebufferobject.readFB->hwid); idReadBuffer = toCtx->framebufferobject.readFB->readbuffer; } - else if (idFBO && !toCtx->framebufferobject.readFB) + else if (idReadFBO && !toCtx->framebufferobject.readFB) { - diff_api.BindFramebufferEXT(GL_READ_FRAMEBUFFER, idFBO); + diff_api.BindFramebufferEXT(GL_READ_FRAMEBUFFER, idReadFBO); idReadBuffer = GL_COLOR_ATTACHMENT0; } |
