/* Copyright (c) 2001, Stanford University * All rights reserved * * See the file LICENSE.txt for information on redistributing this software. */ #include "server_dispatch.h" #include "server.h" #include "cr_error.h" #include "cr_mem.h" #include "cr_string.h" #include "cr_pixeldata.h" #ifdef VBOX_WITH_CRDUMPER # include "cr_dump.h" #endif void SERVER_DISPATCH_APIENTRY crServerDispatchSelectBuffer( GLsizei size, GLuint *buffer ) { (void) size; (void) buffer; crError( "Unsupported network glSelectBuffer call." ); } void SERVER_DISPATCH_APIENTRY crServerDispatchGetChromiumParametervCR(GLenum target, GLuint index, GLenum type, GLsizei count, GLvoid *values) { GLubyte local_storage[4096]; GLint bytes = 0; switch (type) { case GL_BYTE: case GL_UNSIGNED_BYTE: bytes = count * sizeof(GLbyte); break; case GL_SHORT: case GL_UNSIGNED_SHORT: bytes = count * sizeof(GLshort); break; case GL_INT: case GL_UNSIGNED_INT: bytes = count * sizeof(GLint); break; case GL_FLOAT: bytes = count * sizeof(GLfloat); break; case GL_DOUBLE: bytes = count * sizeof(GLdouble); break; default: crError("Bad type in crServerDispatchGetChromiumParametervCR"); } CRASSERT(bytes >= 0); CRASSERT(bytes < 4096); switch (target) { case GL_DBG_CHECK_BREAK_CR: { if (bytes > 0) { GLubyte *pbRc = local_storage; GLuint *puRc = (GLuint *)(bytes >=4 ? local_storage : NULL); int rc; memset(local_storage, 0, bytes); if (cr_server.RcToGuestOnce) { rc = cr_server.RcToGuestOnce; cr_server.RcToGuestOnce = 0; } else { rc = cr_server.RcToGuest; } if (puRc) *puRc = rc; else *pbRc = !!rc; } else { crWarning("zero bytes for GL_DBG_CHECK_BREAK_CR"); } break; } case GL_HH_SET_DEFAULT_SHARED_CTX: WARN(("Recieved GL_HH_SET_DEFAULT_SHARED_CTX from guest, ignoring")); break; case GL_HH_SET_CLIENT_CALLOUT: WARN(("Recieved GL_HH_SET_CLIENT_CALLOUT from guest, ignoring")); break; default: cr_server.head_spu->dispatch_table.GetChromiumParametervCR( target, index, type, count, local_storage ); break; } crServerReturnValue( local_storage, bytes ); } void SERVER_DISPATCH_APIENTRY crServerDispatchChromiumParametervCR(GLenum target, GLenum type, GLsizei count, const GLvoid *values) { CRMuralInfo *mural = cr_server.curClient->currentMural; static int gather_connect_count = 0; switch (target) { case GL_SHARE_LISTS_CR: { CRContextInfo *pCtx[2]; GLint *ai32Values; int i; if (count != 2) { WARN(("GL_SHARE_LISTS_CR invalid cound %d", count)); return; } if (type != GL_UNSIGNED_INT && type != GL_INT) { WARN(("GL_SHARE_LISTS_CR invalid type %d", type)); return; } ai32Values = (GLint*)values; for (i = 0; i < 2; ++i) { const int32_t val = ai32Values[i]; if (val == 0) { WARN(("GL_SHARE_LISTS_CR invalid value[%d] %d", i, val)); return; } pCtx[i] = (CRContextInfo *) crHashtableSearch(cr_server.contextTable, val); if (!pCtx[i]) { WARN(("GL_SHARE_LISTS_CR invalid pCtx1 for value[%d] %d", i, val)); return; } if (!pCtx[i]->pContext) { WARN(("GL_SHARE_LISTS_CR invalid pCtx1 pContext for value[%d] %d", i, val)); return; } } crStateShareLists(pCtx[0]->pContext, pCtx[1]->pContext); break; } case GL_SET_MAX_VIEWPORT_CR: { GLint *maxDims = (GLint *)values; cr_server.limits.maxViewportDims[0] = maxDims[0]; cr_server.limits.maxViewportDims[1] = maxDims[1]; } break; case GL_TILE_INFO_CR: /* message from tilesort SPU to set new tile bounds */ { GLint numTiles, muralWidth, muralHeight, server, tiles; GLint *tileBounds; CRASSERT(count >= 4); CRASSERT((count - 4) % 4 == 0); /* must be multiple of four */ CRASSERT(type == GL_INT); numTiles = (count - 4) / 4; tileBounds = (GLint *) values; server = tileBounds[0]; muralWidth = tileBounds[1]; muralHeight = tileBounds[2]; tiles = tileBounds[3]; CRASSERT(tiles == numTiles); tileBounds += 4; /* skip over header values */ /*crServerNewMuralTiling(mural, muralWidth, muralHeight, numTiles, tileBounds); mural->viewportValidated = GL_FALSE;*/ } break; case GL_GATHER_DRAWPIXELS_CR: if (cr_server.only_swap_once && cr_server.curClient != cr_server.clients[0]) break; cr_server.head_spu->dispatch_table.ChromiumParametervCR( target, type, count, values ); break; case GL_GATHER_CONNECT_CR: /* * We want the last connect to go through, * otherwise we might deadlock in CheckWindowSize() * in the readback spu */ gather_connect_count++; if (cr_server.only_swap_once && (gather_connect_count != cr_server.numClients)) { break; } cr_server.head_spu->dispatch_table.ChromiumParametervCR( target, type, count, values ); gather_connect_count = 0; break; case GL_SERVER_VIEW_MATRIX_CR: /* Set this server's view matrix which will get premultiplied onto the * modelview matrix. For non-planar tilesort and stereo. */ CRASSERT(count == 18); CRASSERT(type == GL_FLOAT); /* values[0] is the server index. Ignored here but used in tilesort SPU */ /* values[1] is the left/right eye index (0 or 1) */ { const GLfloat *v = (const GLfloat *) values; const int eye = v[1] == 0.0 ? 0 : 1; crMatrixInitFromFloats(&cr_server.viewMatrix[eye], v + 2); crDebug("Got GL_SERVER_VIEW_MATRIX_CR:\n" " %f %f %f %f\n" " %f %f %f %f\n" " %f %f %f %f\n" " %f %f %f %f", cr_server.viewMatrix[eye].m00, cr_server.viewMatrix[eye].m10, cr_server.viewMatrix[eye].m20, cr_server.viewMatrix[eye].m30, cr_server.viewMatrix[eye].m01, cr_server.viewMatrix[eye].m11, cr_server.viewMatrix[eye].m21, cr_server.viewMatrix[eye].m31, cr_server.viewMatrix[eye].m02, cr_server.viewMatrix[eye].m12, cr_server.viewMatrix[eye].m22, cr_server.viewMatrix[eye].m32, cr_server.viewMatrix[eye].m03, cr_server.viewMatrix[eye].m13, cr_server.viewMatrix[eye].m23, cr_server.viewMatrix[eye].m33); } cr_server.viewOverride = GL_TRUE; break; case GL_SERVER_PROJECTION_MATRIX_CR: /* Set this server's projection matrix which will get replace the user's * projection matrix. For non-planar tilesort and stereo. */ CRASSERT(count == 18); CRASSERT(type == GL_FLOAT); /* values[0] is the server index. Ignored here but used in tilesort SPU */ /* values[1] is the left/right eye index (0 or 1) */ { const GLfloat *v = (const GLfloat *) values; const int eye = v[1] == 0.0 ? 0 : 1; crMatrixInitFromFloats(&cr_server.projectionMatrix[eye], v + 2); crDebug("Got GL_SERVER_PROJECTION_MATRIX_CR:\n" " %f %f %f %f\n" " %f %f %f %f\n" " %f %f %f %f\n" " %f %f %f %f", cr_server.projectionMatrix[eye].m00, cr_server.projectionMatrix[eye].m10, cr_server.projectionMatrix[eye].m20, cr_server.projectionMatrix[eye].m30, cr_server.projectionMatrix[eye].m01, cr_server.projectionMatrix[eye].m11, cr_server.projectionMatrix[eye].m21, cr_server.projectionMatrix[eye].m31, cr_server.projectionMatrix[eye].m02, cr_server.projectionMatrix[eye].m12, cr_server.projectionMatrix[eye].m22, cr_server.projectionMatrix[eye].m32, cr_server.projectionMatrix[eye].m03, cr_server.projectionMatrix[eye].m13, cr_server.projectionMatrix[eye].m23, cr_server.projectionMatrix[eye].m33); if (cr_server.projectionMatrix[eye].m33 == 0.0f) { float x = cr_server.projectionMatrix[eye].m00; float y = cr_server.projectionMatrix[eye].m11; float a = cr_server.projectionMatrix[eye].m20; float b = cr_server.projectionMatrix[eye].m21; float c = cr_server.projectionMatrix[eye].m22; float d = cr_server.projectionMatrix[eye].m32; float znear = -d / (1.0f - c); float zfar = (c - 1.0f) * znear / (c + 1.0f); float left = znear * (a - 1.0f) / x; float right = 2.0f * znear / x + left; float bottom = znear * (b - 1.0f) / y; float top = 2.0f * znear / y + bottom; crDebug("Frustum: left, right, bottom, top, near, far: %f, %f, %f, %f, %f, %f", left, right, bottom, top, znear, zfar); } else { /* Todo: Add debug output for orthographic projection*/ } } cr_server.projectionOverride = GL_TRUE; break; case GL_HH_SET_TMPCTX_MAKE_CURRENT: /*we should not receive it from the guest! */ break; case GL_HH_SET_CLIENT_CALLOUT: WARN(("Recieved GL_HH_SET_CLIENT_CALLOUT from guest, ignoring")); break; default: /* Pass the parameter info to the head SPU */ cr_server.head_spu->dispatch_table.ChromiumParametervCR( target, type, count, values ); break; } } void SERVER_DISPATCH_APIENTRY crServerDispatchChromiumParameteriCR(GLenum target, GLint value) { switch (target) { case GL_SHARE_CONTEXT_RESOURCES_CR: crStateShareContext(value); break; case GL_RCUSAGE_TEXTURE_SET_CR: crStateSetTextureUsed(value, GL_TRUE); break; case GL_RCUSAGE_TEXTURE_CLEAR_CR: crStateSetTextureUsed(value, GL_FALSE); break; case GL_PIN_TEXTURE_SET_CR: crStatePinTexture(value, GL_TRUE); break; case GL_PIN_TEXTURE_CLEAR_CR: crStatePinTexture(value, GL_FALSE); break; case GL_SHARED_DISPLAY_LISTS_CR: cr_server.sharedDisplayLists = value; break; case GL_SHARED_TEXTURE_OBJECTS_CR: cr_server.sharedTextureObjects = value; break; case GL_SHARED_PROGRAMS_CR: cr_server.sharedPrograms = value; break; case GL_SERVER_CURRENT_EYE_CR: cr_server.currentEye = value ? 1 : 0; break; case GL_HOST_WND_CREATED_HIDDEN_CR: cr_server.bWindowsInitiallyHidden = value ? 1 : 0; break; case GL_HH_SET_DEFAULT_SHARED_CTX: WARN(("Recieved GL_HH_SET_DEFAULT_SHARED_CTX from guest, ignoring")); break; case GL_HH_RENDERTHREAD_INFORM: WARN(("Recieved GL_HH_RENDERTHREAD_INFORM from guest, ignoring")); break; default: /* Pass the parameter info to the head SPU */ cr_server.head_spu->dispatch_table.ChromiumParameteriCR( target, value ); } } void SERVER_DISPATCH_APIENTRY crServerDispatchChromiumParameterfCR(GLenum target, GLfloat value) { switch (target) { case GL_SHARED_DISPLAY_LISTS_CR: cr_server.sharedDisplayLists = (int) value; break; case GL_SHARED_TEXTURE_OBJECTS_CR: cr_server.sharedTextureObjects = (int) value; break; case GL_SHARED_PROGRAMS_CR: cr_server.sharedPrograms = (int) value; break; default: /* Pass the parameter info to the head SPU */ cr_server.head_spu->dispatch_table.ChromiumParameterfCR( target, value ); } } GLint crServerGenerateID(GLint *pCounter) { return (*pCounter)++; } /*#define CR_DUMP_BLITS*/ #ifdef CR_DUMP_BLITS static int blitnum=0; static int copynum=0; #endif # ifdef DEBUG_misha //# define CR_CHECK_BLITS # include # undef CRASSERT /* iprt assert's int3 are inlined that is why are more convenient to use since they can be easily disabled individually */ # define CRASSERT Assert # endif void SERVER_DISPATCH_APIENTRY crServerDispatchCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) { /*@todo pbo/fbo disabled for now as it's slower, check on other gpus*/ static int siHavePBO = 0; static int siHaveFBO = 0; if ((target!=GL_TEXTURE_2D) || (height>=0)) { cr_server.head_spu->dispatch_table.CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height); #ifdef CR_DUMP_BLITS { SPUDispatchTable *gl = &cr_server.head_spu->dispatch_table; void *img; GLint w, h; char fname[200]; copynum++; gl->GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w); gl->GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h); img = crAlloc(w*h*4); CRASSERT(img); gl->GetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, img); sprintf(fname, "copy_blit%i_copy_%i.tga", blitnum, copynum); crDumpNamedTGA(fname, w, h, img); crFree(img); } #endif } else /* negative height, means we have to Yinvert the source pixels while copying */ { SPUDispatchTable *gl = &cr_server.head_spu->dispatch_table; if (siHavePBO<0) { const char *ext = (const char*)gl->GetString(GL_EXTENSIONS); siHavePBO = crStrstr(ext, "GL_ARB_pixel_buffer_object") ? 1:0; } if (siHaveFBO<0) { const char *ext = (const char*)gl->GetString(GL_EXTENSIONS); siHaveFBO = crStrstr(ext, "GL_EXT_framebuffer_object") ? 1:0; } if (siHavePBO==0 && siHaveFBO==0) { #if 1 GLint dRow, sRow; for (dRow=yoffset, sRow=y-height-1; dRowCopyTexSubImage2D(target, level, xoffset, dRow, x, sRow, width, 1); } #else { GLint w, h, i; char *img1, *img2, *sPtr, *dPtr; CRContext *ctx = crStateGetCurrent(); w = ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D->level[0][level].width; h = ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D->level[0][level].height; img1 = crAlloc(4*w*h); img2 = crAlloc(4*width*(-height)); CRASSERT(img1 && img2); gl->CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, -height); gl->GetTexImage(target, level, GL_RGBA, GL_UNSIGNED_BYTE, img1); sPtr=img1+4*xoffset+4*w*yoffset; dPtr=img2+4*width*(-height-1); for (i=0; i<-height; ++i) { crMemcpy(dPtr, sPtr, 4*width); sPtr += 4*w; dPtr -= 4*width; } gl->TexSubImage2D(target, level, xoffset, yoffset, width, -height, GL_RGBA, GL_UNSIGNED_BYTE, img2); crFree(img1); crFree(img2); } #endif } else if (siHaveFBO==1) /*@todo more states to set and restore here*/ { GLuint tID, fboID; GLenum status; CRContext *ctx = crStateGetCurrent(); gl->GenTextures(1, &tID); gl->BindTexture(target, tID); gl->CopyTexImage2D(target, level, GL_RGBA, x, y, width, -height, 0); gl->GenFramebuffersEXT(1, &fboID); gl->BindFramebufferEXT(GL_FRAMEBUFFER_EXT, fboID); gl->FramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, target, ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D->hwid, level); status = gl->CheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { crWarning("Framebuffer status 0x%x", status); } gl->Enable(target); gl->PushAttrib(GL_VIEWPORT_BIT); gl->Viewport(xoffset, yoffset, width, -height); gl->MatrixMode(GL_PROJECTION); gl->PushMatrix(); gl->LoadIdentity(); gl->MatrixMode(GL_MODELVIEW); gl->PushMatrix(); gl->LoadIdentity(); gl->Disable(GL_DEPTH_TEST); gl->Disable(GL_CULL_FACE); gl->Disable(GL_STENCIL_TEST); gl->Disable(GL_SCISSOR_TEST); gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); gl->TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); gl->Begin(GL_QUADS); gl->TexCoord2f(0.0f, 1.0f); gl->Vertex2f(-1.0, -1.0); gl->TexCoord2f(0.0f, 0.0f); gl->Vertex2f(-1.0f, 1.0f); gl->TexCoord2f(1.0f, 0.0f); gl->Vertex2f(1.0f, 1.0f); gl->TexCoord2f(1.0f, 1.0f); gl->Vertex2f(1.0f, -1.0f); gl->End(); gl->PopMatrix(); gl->MatrixMode(GL_PROJECTION); gl->PopMatrix(); gl->PopAttrib(); gl->FramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, target, 0, level); gl->BindFramebufferEXT(GL_FRAMEBUFFER_EXT, ctx->framebufferobject.drawFB ? ctx->framebufferobject.drawFB->hwid:0); gl->BindTexture(target, ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D->hwid); gl->DeleteFramebuffersEXT(1, &fboID); gl->DeleteTextures(1, &tID); #if 0 { GLint dRow, sRow, w, h; void *img1, *img2; w = ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D->level[0][level].width; h = ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D->level[0][level].height; img1 = crAlloc(4*w*h); img2 = crAlloc(4*w*h); CRASSERT(img1 && img2); gl->GetTexImage(target, level, GL_BGRA, GL_UNSIGNED_BYTE, img1); for (dRow=yoffset, sRow=y-height-1; dRowCopyTexSubImage2D(target, level, xoffset, dRow, x, sRow, width, 1); } gl->GetTexImage(target, level, GL_BGRA, GL_UNSIGNED_BYTE, img2); if (crMemcmp(img1, img2, 4*w*h)) { crDebug("MISMATCH! (%x, %i, ->%i,%i <-%i, %i [%ix%i])", target, level, xoffset, yoffset, x, y, width, height); crDumpTGA(w, h, img1); crDumpTGA(w, h, img2); DebugBreak(); } crFree(img1); crFree(img2); } #endif } else { GLuint pboId, dRow, sRow; CRContext *ctx = crStateGetCurrent(); gl->GenBuffersARB(1, &pboId); gl->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pboId); gl->BufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, -width*height*4, 0, GL_STATIC_COPY_ARB); #if 1 gl->ReadPixels(x, y, width, -height, GL_RGBA, GL_UNSIGNED_BYTE, 0); gl->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, ctx->bufferobject.packBuffer->hwid); gl->BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pboId); for (dRow=yoffset, sRow=-height-1; dRowTexSubImage2D(target, level, xoffset, dRow, width, 1, GL_RGBA, GL_UNSIGNED_BYTE, (void*)((uintptr_t)sRow*width*4)); } #else /*few times slower again*/ for (dRow=0, sRow=y-height-1; dRow<-height; dRow++, sRow--) { gl->ReadPixels(x, sRow, width, 1, GL_RGBA, GL_UNSIGNED_BYTE, (void*)((uintptr_t)dRow*width*4)); } gl->BindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, ctx->bufferobject.packBuffer->hwid); gl->BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pboId); gl->TexSubImage2D(target, level, xoffset, yoffset, width, -height, GL_RGBA, GL_UNSIGNED_BYTE, 0); #endif gl->BindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, ctx->bufferobject.unpackBuffer->hwid); gl->DeleteBuffersARB(1, &pboId); } } } #ifdef CR_CHECK_BLITS void crDbgFree(void *pvData) { crFree(pvData); } void crDbgGetTexImage2D(GLint texTarget, GLint texName, GLvoid **ppvImage, GLint *pw, GLint *ph) { SPUDispatchTable *gl = &cr_server.head_spu->dispatch_table; GLint ppb, pub, dstw, dsth, otex; GLint pa, pr, psp, psr, ua, ur, usp, usr; GLvoid *pvImage; GLint rfb, dfb, rb, db; gl->GetIntegerv(GL_READ_FRAMEBUFFER_BINDING_EXT, &rfb); gl->GetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING_EXT, &dfb); gl->GetIntegerv(GL_READ_BUFFER, &rb); gl->GetIntegerv(GL_DRAW_BUFFER, &db); gl->BindFramebufferEXT(GL_READ_FRAMEBUFFER_BINDING_EXT, 0); gl->BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_BINDING_EXT, 0); gl->ReadBuffer(GL_BACK); gl->DrawBuffer(GL_BACK); gl->GetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING, &ppb); gl->GetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &pub); gl->GetIntegerv(GL_TEXTURE_BINDING_2D, &otex); gl->GetIntegerv(GL_PACK_ROW_LENGTH, &pr); gl->GetIntegerv(GL_PACK_ALIGNMENT, &pa); gl->GetIntegerv(GL_PACK_SKIP_PIXELS, &psp); gl->GetIntegerv(GL_PACK_SKIP_ROWS, &psr); gl->GetIntegerv(GL_UNPACK_ROW_LENGTH, &ur); gl->GetIntegerv(GL_UNPACK_ALIGNMENT, &ua); gl->GetIntegerv(GL_UNPACK_SKIP_PIXELS, &usp); gl->GetIntegerv(GL_UNPACK_SKIP_ROWS, &usr); gl->BindTexture(texTarget, texName); gl->GetTexLevelParameteriv(texTarget, 0, GL_TEXTURE_WIDTH, &dstw); gl->GetTexLevelParameteriv(texTarget, 0, GL_TEXTURE_HEIGHT, &dsth); gl->PixelStorei(GL_PACK_ROW_LENGTH, 0); gl->PixelStorei(GL_PACK_ALIGNMENT, 1); gl->PixelStorei(GL_PACK_SKIP_PIXELS, 0); gl->PixelStorei(GL_PACK_SKIP_ROWS, 0); gl->PixelStorei(GL_UNPACK_ROW_LENGTH, 0); gl->PixelStorei(GL_UNPACK_ALIGNMENT, 1); gl->PixelStorei(GL_UNPACK_SKIP_PIXELS, 0); gl->PixelStorei(GL_UNPACK_SKIP_ROWS, 0); gl->BindBufferARB(GL_PIXEL_PACK_BUFFER, 0); gl->BindBufferARB(GL_PIXEL_UNPACK_BUFFER, 0); pvImage = crAlloc(4*dstw*dsth); gl->GetTexImage(texTarget, 0, GL_BGRA, GL_UNSIGNED_BYTE, pvImage); gl->BindTexture(texTarget, otex); gl->PixelStorei(GL_PACK_ROW_LENGTH, pr); gl->PixelStorei(GL_PACK_ALIGNMENT, pa); gl->PixelStorei(GL_PACK_SKIP_PIXELS, psp); gl->PixelStorei(GL_PACK_SKIP_ROWS, psr); gl->PixelStorei(GL_UNPACK_ROW_LENGTH, ur); gl->PixelStorei(GL_UNPACK_ALIGNMENT, ua); gl->PixelStorei(GL_UNPACK_SKIP_PIXELS, usp); gl->PixelStorei(GL_UNPACK_SKIP_ROWS, usr); gl->BindBufferARB(GL_PIXEL_PACK_BUFFER, ppb); gl->BindBufferARB(GL_PIXEL_UNPACK_BUFFER, pub); gl->BindFramebufferEXT(GL_READ_FRAMEBUFFER_BINDING_EXT, rfb); gl->BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_BINDING_EXT, dfb); gl->ReadBuffer(rb); gl->DrawBuffer(db); *ppvImage = pvImage; *pw = dstw; *ph = dsth; } DECLEXPORT(void) crDbgPrint(const char *format, ... ) { va_list args; static char txt[8092]; va_start( args, format ); vsprintf( txt, format, args ); OutputDebugString(txt); } void crDbgDumpImage2D(const char* pszDesc, const void *pvData, uint32_t width, uint32_t height, uint32_t bpp, uint32_t pitch) { crDbgPrint("%s, ( !vbvdbg.ms 0x%p 0n%d 0n%d 0n%d 0n%d )\n", pvData, width, height, bpp, pitch, pszDesc, pvData, width, height, bpp, pitch); } void crDbgDumpTexImage2D(const char* pszDesc, GLint texTarget, GLint texName, GLboolean fBreak) { GLvoid *pvImage; GLint w, h; crDbgGetTexImage2D(texTarget, texName, &pvImage, &w, &h); crDbgPrint("%s target(%d), name(%d), width(%d), height(%d)", pszDesc, texTarget, texName, w, h); crDbgDumpImage2D("texture data", pvImage, w, h, 32, (32 * w)/8); if (fBreak) { CRASSERT(0); } crDbgFree(pvImage); } #endif PCR_BLITTER crServerVBoxBlitterGet() { if (!CrBltIsInitialized(&cr_server.Blitter)) { CR_BLITTER_CONTEXT Ctx; int rc; CRASSERT(cr_server.MainContextInfo.SpuContext); Ctx.Base.id = cr_server.MainContextInfo.SpuContext; Ctx.Base.visualBits = cr_server.MainContextInfo.CreateInfo.realVisualBits; rc = CrBltInit(&cr_server.Blitter, &Ctx, true, true, NULL, &cr_server.TmpCtxDispatch); if (RT_SUCCESS(rc)) { CRASSERT(CrBltIsInitialized(&cr_server.Blitter)); } else { crWarning("CrBltInit failed, rc %d", rc); CRASSERT(!CrBltIsInitialized(&cr_server.Blitter)); return NULL; } } if (!CrBltMuralGetCurrentInfo(&cr_server.Blitter)->Base.id) { CRMuralInfo *dummy = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.realVisualBits); CR_BLITTER_WINDOW DummyInfo; CRASSERT(dummy); crServerVBoxBlitterWinInit(&DummyInfo, dummy); CrBltMuralSetCurrentInfo(&cr_server.Blitter, &DummyInfo); } return &cr_server.Blitter; } PCR_BLITTER crServerVBoxBlitterGetInitialized() { if (CrBltIsInitialized(&cr_server.Blitter)) return &cr_server.Blitter; return NULL; } int crServerVBoxBlitterTexInit(CRContext *ctx, CRMuralInfo *mural, PVBOXVR_TEXTURE pTex, GLboolean fDraw) { CRTextureObj *tobj; CRFramebufferObjectState *pBuf = &ctx->framebufferobject; GLenum enmBuf; CRFBOAttachmentPoint *pAp; GLuint idx; CRTextureLevel *tl; CRFramebufferObject *pFBO = fDraw ? pBuf->drawFB : pBuf->readFB; if (!pFBO) { GLuint hwid; if (!mural->fRedirected) { WARN(("mural not redirected!")); return VERR_NOT_IMPLEMENTED; } enmBuf = fDraw ? ctx->buffer.drawBuffer : ctx->buffer.readBuffer; switch (enmBuf) { case GL_BACK: case GL_BACK_RIGHT: case GL_BACK_LEFT: hwid = mural->aidColorTexs[CR_SERVER_FBO_BB_IDX(mural)]; break; case GL_FRONT: case GL_FRONT_RIGHT: case GL_FRONT_LEFT: hwid = mural->aidColorTexs[CR_SERVER_FBO_FB_IDX(mural)]; break; default: WARN(("unsupported enum buf %d", enmBuf)); return VERR_NOT_IMPLEMENTED; break; } if (!hwid) { crWarning("offscreen render tex hwid is null"); return VERR_INVALID_STATE; } pTex->width = mural->width; pTex->height = mural->height; pTex->target = GL_TEXTURE_2D; pTex->hwid = hwid; return VINF_SUCCESS; } enmBuf = fDraw ? pFBO->drawbuffer[0] : pFBO->readbuffer; idx = enmBuf - GL_COLOR_ATTACHMENT0_EXT; if (idx >= CR_MAX_COLOR_ATTACHMENTS) { crWarning("idx is invalid %d, using 0", idx); } pAp = &pFBO->color[idx]; if (!pAp->name) { crWarning("no collor draw attachment"); return VERR_INVALID_STATE; } if (pAp->level) { WARN(("non-zero level not implemented")); return VERR_NOT_IMPLEMENTED; } tobj = (CRTextureObj*)crHashtableSearch(ctx->shared->textureTable, pAp->name); if (!tobj) { crWarning("no texture object found for name %d", pAp->name); return VERR_INVALID_STATE; } if (tobj->target != GL_TEXTURE_2D && tobj->target != GL_TEXTURE_RECTANGLE_NV) { WARN(("non-texture[rect|2d] not implemented")); return VERR_NOT_IMPLEMENTED; } CRASSERT(tobj->hwid); tl = tobj->level[0]; pTex->width = tl->width; pTex->height = tl->height; pTex->target = tobj->target; pTex->hwid = tobj->hwid; return VINF_SUCCESS; } int crServerVBoxBlitterBlitCurrentCtx(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { PCR_BLITTER pBlitter; CR_BLITTER_CONTEXT Ctx; CRMuralInfo *mural; CRContext *ctx = crStateGetCurrent(); PVBOXVR_TEXTURE pDrawTex, pReadTex; VBOXVR_TEXTURE DrawTex, ReadTex; int rc; GLuint idDrawFBO, idReadFBO; CR_BLITTER_WINDOW BltInfo; if (mask != GL_COLOR_BUFFER_BIT) { WARN(("not supported blit mask %d", mask)); return VERR_NOT_IMPLEMENTED; } if (!cr_server.curClient) { crWarning("no current client"); return VERR_INVALID_STATE; } mural = cr_server.curClient->currentMural; if (!mural) { crWarning("no current mural"); return VERR_INVALID_STATE; } rc = crServerVBoxBlitterTexInit(ctx, mural, &DrawTex, GL_TRUE); if (RT_SUCCESS(rc)) { pDrawTex = &DrawTex; } else { crWarning("crServerVBoxBlitterTexInit failed for draw"); return rc; } rc = crServerVBoxBlitterTexInit(ctx, mural, &ReadTex, GL_FALSE); if (RT_SUCCESS(rc)) { pReadTex = &ReadTex; } else { // crWarning("crServerVBoxBlitterTexInit failed for read"); return rc; } pBlitter = crServerVBoxBlitterGet(); if (!pBlitter) { crWarning("crServerVBoxBlitterGet failed"); return VERR_GENERAL_FAILURE; } crServerVBoxBlitterWinInit(&BltInfo, mural); crServerVBoxBlitterCtxInit(&Ctx, cr_server.curClient->currentCtxInfo); CrBltMuralSetCurrentInfo(pBlitter, &BltInfo); idDrawFBO = CR_SERVER_FBO_FOR_IDX(mural, mural->iCurDrawBuffer); idReadFBO = CR_SERVER_FBO_FOR_IDX(mural, mural->iCurReadBuffer); crStateSwitchPrepare(NULL, ctx, idDrawFBO, idReadFBO); rc = CrBltEnter(pBlitter); if (RT_SUCCESS(rc)) { RTRECT ReadRect, DrawRect; ReadRect.xLeft = srcX0; ReadRect.yTop = srcY0; ReadRect.xRight = srcX1; ReadRect.yBottom = srcY1; DrawRect.xLeft = dstX0; DrawRect.yTop = dstY0; DrawRect.xRight = dstX1; DrawRect.yBottom = dstY1; CrBltBlitTexTex(pBlitter, pReadTex, &ReadRect, pDrawTex, &DrawRect, 1, CRBLT_FLAGS_FROM_FILTER(filter)); CrBltLeave(pBlitter); } else { crWarning("CrBltEnter failed rc %d", rc); } crStateSwitchPostprocess(ctx, NULL, idDrawFBO, idReadFBO); return rc; } void SERVER_DISPATCH_APIENTRY crServerDispatchBlitFramebufferEXT(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) { CRContext *ctx = crStateGetCurrent(); bool fTryBlitter = false; #ifdef CR_CHECK_BLITS // { SPUDispatchTable *gl = &cr_server.head_spu->dispatch_table; GLint rfb=0, dfb=0, dtex=0, dlev=-1, rtex=0, rlev=-1, rb=0, db=0, ppb=0, pub=0, vp[4], otex, dstw, dsth; GLint sdtex=0, srtex=0; GLenum dStatus, rStatus; CRTextureObj *tobj = 0; CRTextureLevel *tl = 0; GLint id, tuId, pbufId, pbufIdHw, ubufId, ubufIdHw, width, height, depth; crDebug("===StateTracker==="); crDebug("Current TU: %i", ctx->texture.curTextureUnit); tobj = ctx->texture.unit[ctx->texture.curTextureUnit].currentTexture2D; CRASSERT(tobj); tl = &tobj->level[0][0]; crDebug("Texture %i(hw %i), w=%i, h=%i", tobj->id, tobj->hwid, tl->width, tl->height, tl->depth); if (crStateIsBufferBound(GL_PIXEL_PACK_BUFFER_ARB)) { pbufId = ctx->bufferobject.packBuffer->hwid; } else { pbufId = 0; } crDebug("Pack BufferId %i", pbufId); if (crStateIsBufferBound(GL_PIXEL_UNPACK_BUFFER_ARB)) { ubufId = ctx->bufferobject.unpackBuffer->hwid; } else { ubufId = 0; } crDebug("Unpack BufferId %i", ubufId); crDebug("===GPU==="); cr_server.head_spu->dispatch_table.GetIntegerv(GL_ACTIVE_TEXTURE, &tuId); crDebug("Current TU: %i", tuId - GL_TEXTURE0_ARB); CRASSERT(tuId - GL_TEXTURE0_ARB == ctx->texture.curTextureUnit); cr_server.head_spu->dispatch_table.GetIntegerv(GL_TEXTURE_BINDING_2D, &id); cr_server.head_spu->dispatch_table.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width); cr_server.head_spu->dispatch_table.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height); cr_server.head_spu->dispatch_table.GetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_DEPTH, &depth); crDebug("Texture: %i, w=%i, h=%i, d=%i", id, width, height, depth); CRASSERT(id == tobj->hwid); CRASSERT(width == tl->width); CRASSERT(height == tl->height); CRASSERT(depth == tl->depth); cr_server.head_spu->dispatch_table.GetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING, &pbufIdHw); crDebug("Hw Pack BufferId %i", pbufIdHw); CRASSERT(pbufIdHw == pbufId); cr_server.head_spu->dispatch_table.GetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &ubufIdHw); crDebug("Hw Unpack BufferId %i", ubufIdHw); CRASSERT(ubufIdHw == ubufId); gl->GetIntegerv(GL_READ_FRAMEBUFFER_BINDING_EXT, &rfb); gl->GetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING_EXT, &dfb); gl->GetIntegerv(GL_READ_BUFFER, &rb); gl->GetIntegerv(GL_DRAW_BUFFER, &db); gl->GetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING, &ppb); gl->GetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &pub); gl->GetIntegerv(GL_VIEWPORT, &vp[0]); gl->GetIntegerv(GL_TEXTURE_BINDING_2D, &otex); gl->GetFramebufferAttachmentParameterivEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT, &dtex); gl->GetFramebufferAttachmentParameterivEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT, &dlev); dStatus = gl->CheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT); gl->GetFramebufferAttachmentParameterivEXT(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT, &rtex); gl->GetFramebufferAttachmentParameterivEXT(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT, &rlev); rStatus = gl->CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER_EXT); if (dtex) { CRASSERT(!dlev); } if (rtex) { CRASSERT(!rlev); } if (ctx->framebufferobject.drawFB) { CRASSERT(dfb); CRASSERT(ctx->framebufferobject.drawFB->hwid == dfb); CRASSERT(ctx->framebufferobject.drawFB->drawbuffer[0] == db); CRASSERT(dStatus==GL_FRAMEBUFFER_COMPLETE_EXT); CRASSERT(db==GL_COLOR_ATTACHMENT0_EXT); CRASSERT(ctx->framebufferobject.drawFB->color[0].type == GL_TEXTURE); CRASSERT(ctx->framebufferobject.drawFB->color[0].level == 0); sdtex = ctx->framebufferobject.drawFB->color[0].name; sdtex = crStateGetTextureHWID(sdtex); CRASSERT(sdtex); } else { CRASSERT(!dfb); } if (ctx->framebufferobject.readFB) { CRASSERT(rfb); CRASSERT(ctx->framebufferobject.readFB->hwid == rfb); CRASSERT(rStatus==GL_FRAMEBUFFER_COMPLETE_EXT); CRASSERT(ctx->framebufferobject.readFB->color[0].type == GL_TEXTURE); CRASSERT(ctx->framebufferobject.readFB->color[0].level == 0); srtex = ctx->framebufferobject.readFB->color[0].name; srtex = crStateGetTextureHWID(srtex); CRASSERT(srtex); } else { CRASSERT(!rfb); } CRASSERT(sdtex == dtex); CRASSERT(srtex == rtex); // crDbgDumpTexImage2D("==> src tex:", GL_TEXTURE_2D, rtex, true); // crDbgDumpTexImage2D("==> dst tex:", GL_TEXTURE_2D, dtex, true); // } #endif #ifdef CR_DUMP_BLITS SPUDispatchTable *gl = &cr_server.head_spu->dispatch_table; GLint rfb=0, dfb=0, dtex=0, dlev=-1, rb=0, db=0, ppb=0, pub=0, vp[4], otex, dstw, dsth; GLenum status; char fname[200]; void *img; blitnum++; crDebug("[%i]BlitFramebufferEXT(%i, %i, %i, %i, %i, %i, %i, %i, %x, %x)", blitnum, srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); crDebug("%i, %i <-> %i, %i", srcX1-srcX0, srcY1-srcY0, dstX1-dstX0, dstY1-dstY0); gl->GetIntegerv(GL_READ_FRAMEBUFFER_BINDING_EXT, &rfb); gl->GetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING_EXT, &dfb); gl->GetIntegerv(GL_READ_BUFFER, &rb); gl->GetIntegerv(GL_DRAW_BUFFER, &db); gl->GetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING, &ppb); gl->GetIntegerv(GL_PIXEL_UNPACK_BUFFER_BINDING, &pub); gl->GetIntegerv(GL_VIEWPORT, &vp[0]); gl->GetIntegerv(GL_TEXTURE_BINDING_2D, &otex); CRASSERT(!rfb && dfb); gl->GetFramebufferAttachmentParameterivEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT, &dtex); gl->GetFramebufferAttachmentParameterivEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT, &dlev); status = gl->CheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT); CRASSERT(status==GL_FRAMEBUFFER_COMPLETE_EXT && db==GL_COLOR_ATTACHMENT0_EXT && (rb==GL_FRONT || rb==GL_BACK) && !rfb && dfb && dtex && !dlev && !ppb && !pub); crDebug("Src[rb 0x%x, fbo %i] Dst[db 0x%x, fbo %i(0x%x), tex %i.%i]", rb, rfb, db, dfb, status, dtex, dlev); crDebug("Viewport [%i, %i, %i, %i]", vp[0], vp[1], vp[2], vp[3]); gl->PixelStorei(GL_PACK_ROW_LENGTH, 0); gl->PixelStorei(GL_PACK_ALIGNMENT, 1); gl->PixelStorei(GL_PACK_SKIP_PIXELS, 0); gl->PixelStorei(GL_PACK_SKIP_ROWS, 0); gl->PixelStorei(GL_UNPACK_ROW_LENGTH, 0); gl->PixelStorei(GL_UNPACK_ALIGNMENT, 1); gl->PixelStorei(GL_UNPACK_SKIP_PIXELS, 0); gl->PixelStorei(GL_UNPACK_SKIP_ROWS, 0); gl->BindTexture(GL_TEXTURE_2D, dtex); gl->GetTexLevelParameteriv(GL_TEXTURE_2D, dlev, GL_TEXTURE_WIDTH, &dstw); gl->GetTexLevelParameteriv(GL_TEXTURE_2D, dlev, GL_TEXTURE_HEIGHT, &dsth); gl->BindTexture(GL_TEXTURE_2D, otex); crDebug("Dst is %i, %i", dstw, dsth); CRASSERT(vp[2]>=dstw && vp[3]>=dsth); img = crAlloc(vp[2]*vp[3]*4); CRASSERT(img); gl->ReadPixels(0, 0, vp[2], vp[3], GL_BGRA, GL_UNSIGNED_BYTE, img); sprintf(fname, "blit%iA_src.tga", blitnum); crDumpNamedTGA(fname, vp[2], vp[3], img); gl->BindTexture(GL_TEXTURE_2D, dtex); gl->GetTexImage(GL_TEXTURE_2D, dlev, GL_BGRA, GL_UNSIGNED_BYTE, img); sprintf(fname, "blit%iB_dst.tga", blitnum); crDumpNamedTGA(fname, dstw, dsth, img); gl->BindTexture(GL_TEXTURE_2D, otex); #endif if (srcY0 > srcY1) { /* work around Intel driver bug on Linux host */ if (1 || dstY0 > dstY1) { /* use srcY1 < srcY2 && dstY1 < dstY2 whenever possible to avoid GPU driver bugs */ int32_t tmp = srcY0; srcY0 = srcY1; srcY1 = tmp; tmp = dstY0; dstY0 = dstY1; dstY1 = tmp; } } if (srcX0 > srcX1) { if (dstX0 > dstX1) { /* use srcX1 < srcX2 && dstX1 < dstX2 whenever possible to avoid GPU driver bugs */ int32_t tmp = srcX0; srcX0 = srcX1; srcX1 = tmp; tmp = dstX0; dstX0 = dstX1; dstX1 = tmp; } } if (cr_server.fBlitterMode) { fTryBlitter = true; } if (fTryBlitter) { int rc = crServerVBoxBlitterBlitCurrentCtx(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); if (RT_SUCCESS(rc)) goto my_exit; } if (ctx->viewport.scissorTest) cr_server.head_spu->dispatch_table.Disable(GL_SCISSOR_TEST); cr_server.head_spu->dispatch_table.BlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter); if (ctx->viewport.scissorTest) cr_server.head_spu->dispatch_table.Enable(GL_SCISSOR_TEST); my_exit: //#ifdef CR_CHECK_BLITS // crDbgDumpTexImage2D("<== src tex:", GL_TEXTURE_2D, rtex, true); // crDbgDumpTexImage2D("<== dst tex:", GL_TEXTURE_2D, dtex, true); //#endif #ifdef CR_DUMP_BLITS gl->BindTexture(GL_TEXTURE_2D, dtex); gl->GetTexImage(GL_TEXTURE_2D, dlev, GL_BGRA, GL_UNSIGNED_BYTE, img); sprintf(fname, "blit%iC_res.tga", blitnum); crDumpNamedTGA(fname, dstw, dsth, img); gl->BindTexture(GL_TEXTURE_2D, otex); crFree(img); #endif return; } void SERVER_DISPATCH_APIENTRY crServerDispatchDrawBuffer( GLenum mode ) { crStateDrawBuffer( mode ); if (!crStateGetCurrent()->framebufferobject.drawFB) { if (mode == GL_FRONT || mode == GL_FRONT_LEFT || mode == GL_FRONT_RIGHT) cr_server.curClient->currentMural->bFbDraw = GL_TRUE; if (crServerIsRedirectedToFBO() && cr_server.curClient->currentMural->aidFBOs[0]) { CRMuralInfo *mural = cr_server.curClient->currentMural; GLint iBufferNeeded = -1; switch (mode) { case GL_BACK: case GL_BACK_LEFT: case GL_BACK_RIGHT: mode = GL_COLOR_ATTACHMENT0; iBufferNeeded = CR_SERVER_FBO_BB_IDX(mural); break; case GL_FRONT: case GL_FRONT_LEFT: case GL_FRONT_RIGHT: mode = GL_COLOR_ATTACHMENT0; iBufferNeeded = CR_SERVER_FBO_FB_IDX(mural); break; case GL_NONE: crDebug("DrawBuffer: GL_NONE"); break; case GL_AUX0: crDebug("DrawBuffer: GL_AUX0"); break; case GL_AUX1: crDebug("DrawBuffer: GL_AUX1"); break; case GL_AUX2: crDebug("DrawBuffer: GL_AUX2"); break; case GL_AUX3: crDebug("DrawBuffer: GL_AUX3"); break; case GL_LEFT: crWarning("DrawBuffer: GL_LEFT not supported properly"); mode = GL_COLOR_ATTACHMENT0; iBufferNeeded = CR_SERVER_FBO_BB_IDX(mural); break; case GL_RIGHT: crWarning("DrawBuffer: GL_RIGHT not supported properly"); mode = GL_COLOR_ATTACHMENT0; iBufferNeeded = CR_SERVER_FBO_BB_IDX(mural); break; case GL_FRONT_AND_BACK: crWarning("DrawBuffer: GL_FRONT_AND_BACK not supported properly"); mode = GL_COLOR_ATTACHMENT0; iBufferNeeded = CR_SERVER_FBO_BB_IDX(mural); break; default: crWarning("DrawBuffer: unexpected mode! 0x%x", mode); iBufferNeeded = mural->iCurDrawBuffer; break; } if (iBufferNeeded != mural->iCurDrawBuffer) { mural->iCurDrawBuffer = iBufferNeeded; cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_DRAW_FRAMEBUFFER, CR_SERVER_FBO_FOR_IDX(mural, iBufferNeeded)); } } } cr_server.head_spu->dispatch_table.DrawBuffer( mode ); } void SERVER_DISPATCH_APIENTRY crServerDispatchReadBuffer( GLenum mode ) { crStateReadBuffer( mode ); if (crServerIsRedirectedToFBO() && cr_server.curClient->currentMural->aidFBOs[0] && !crStateGetCurrent()->framebufferobject.readFB) { CRMuralInfo *mural = cr_server.curClient->currentMural; GLint iBufferNeeded = -1; switch (mode) { case GL_BACK: case GL_BACK_LEFT: case GL_BACK_RIGHT: mode = GL_COLOR_ATTACHMENT0; iBufferNeeded = CR_SERVER_FBO_BB_IDX(mural); break; case GL_FRONT: case GL_FRONT_LEFT: case GL_FRONT_RIGHT: mode = GL_COLOR_ATTACHMENT0; iBufferNeeded = CR_SERVER_FBO_FB_IDX(mural); break; case GL_NONE: crDebug("ReadBuffer: GL_NONE"); break; case GL_AUX0: crDebug("ReadBuffer: GL_AUX0"); break; case GL_AUX1: crDebug("ReadBuffer: GL_AUX1"); break; case GL_AUX2: crDebug("ReadBuffer: GL_AUX2"); break; case GL_AUX3: crDebug("ReadBuffer: GL_AUX3"); break; case GL_LEFT: crWarning("ReadBuffer: GL_LEFT not supported properly"); mode = GL_COLOR_ATTACHMENT0; iBufferNeeded = CR_SERVER_FBO_BB_IDX(mural); break; case GL_RIGHT: crWarning("ReadBuffer: GL_RIGHT not supported properly"); mode = GL_COLOR_ATTACHMENT0; iBufferNeeded = CR_SERVER_FBO_BB_IDX(mural); break; case GL_FRONT_AND_BACK: crWarning("ReadBuffer: GL_FRONT_AND_BACK not supported properly"); mode = GL_COLOR_ATTACHMENT0; iBufferNeeded = CR_SERVER_FBO_BB_IDX(mural); break; default: crWarning("ReadBuffer: unexpected mode! 0x%x", mode); iBufferNeeded = mural->iCurDrawBuffer; break; } Assert(CR_SERVER_FBO_FOR_IDX(mural, mural->iCurReadBuffer)); if (iBufferNeeded != mural->iCurReadBuffer) { mural->iCurReadBuffer = iBufferNeeded; cr_server.head_spu->dispatch_table.BindFramebufferEXT(GL_READ_FRAMEBUFFER, CR_SERVER_FBO_FOR_IDX(mural, iBufferNeeded)); } } cr_server.head_spu->dispatch_table.ReadBuffer( mode ); } GLenum SERVER_DISPATCH_APIENTRY crServerDispatchGetError( void ) { GLenum retval, err; CRContext *ctx = crStateGetCurrent(); retval = ctx->error; err = cr_server.head_spu->dispatch_table.GetError(); if (retval == GL_NO_ERROR) retval = err; else ctx->error = GL_NO_ERROR; /* our impl has a single error flag, so we just loop here to reset all error flags to no_error */ while (err != GL_NO_ERROR) err = cr_server.head_spu->dispatch_table.GetError(); crServerReturnValue( &retval, sizeof(retval) ); return retval; /* WILL PROBABLY BE IGNORED */ } void SERVER_DISPATCH_APIENTRY crServerMakeTmpCtxCurrent( GLint window, GLint nativeWindow, GLint context ) { CRContext *pCtx = crStateGetCurrent(); CRContext *pCurCtx = NULL; GLuint idDrawFBO = 0, idReadFBO = 0; int fDoPrePostProcess = 0; if (pCtx) { CRMuralInfo *pCurrentMural = cr_server.currentMural; pCurCtx = cr_server.currentCtxInfo ? cr_server.currentCtxInfo->pContext : cr_server.MainContextInfo.pContext; Assert(pCurCtx == pCtx); if (!context) { if (pCurrentMural) { Assert(cr_server.currentCtxInfo); context = cr_server.currentCtxInfo->SpuContext > 0 ? cr_server.currentCtxInfo->SpuContext : cr_server.MainContextInfo.SpuContext; window = pCurrentMural->spuWindow; } else { CRMuralInfo * pDummy; Assert(!cr_server.currentCtxInfo); pDummy = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.realVisualBits); context = cr_server.MainContextInfo.SpuContext; window = pDummy->spuWindow; } fDoPrePostProcess = -1; } else { fDoPrePostProcess = 1; } if (pCurrentMural) { idDrawFBO = CR_SERVER_FBO_FOR_IDX(pCurrentMural, pCurrentMural->iCurDrawBuffer); idReadFBO = CR_SERVER_FBO_FOR_IDX(pCurrentMural, pCurrentMural->iCurReadBuffer); } else { idDrawFBO = 0; idReadFBO = 0; } } else { /* this is a GUI thread, so no need to do anything here */ } if (fDoPrePostProcess > 0) crStateSwitchPrepare(NULL, pCurCtx, idDrawFBO, idReadFBO); cr_server.head_spu->dispatch_table.MakeCurrent( window, nativeWindow, context); if (fDoPrePostProcess < 0) crStateSwitchPostprocess(pCurCtx, NULL, idDrawFBO, idReadFBO); } void crServerInitTmpCtxDispatch() { MakeCurrentFunc_t pfnMakeCurrent; crSPUInitDispatchTable(&cr_server.TmpCtxDispatch); crSPUCopyDispatchTable(&cr_server.TmpCtxDispatch, &cr_server.head_spu->dispatch_table); cr_server.TmpCtxDispatch.MakeCurrent = crServerMakeTmpCtxCurrent; pfnMakeCurrent = crServerMakeTmpCtxCurrent; cr_server.head_spu->dispatch_table.ChromiumParametervCR(GL_HH_SET_TMPCTX_MAKE_CURRENT, GL_BYTE, sizeof (void*), &pfnMakeCurrent); } /* dump stuff */ #ifdef VBOX_WITH_CRSERVER_DUMPER # ifndef VBOX_WITH_CRDUMPER # error "VBOX_WITH_CRDUMPER undefined!" # endif /* first four bits are buffer dump config * second four bits are texture dump config * config flags: * 1 - blit on enter * 2 - blit on exit * * * Example: * * 0x03 - dump buffer on enter and exit * 0x22 - dump texture and buffer on exit */ int64_t g_CrDbgDumpPid = 0; unsigned long g_CrDbgDumpEnabled = 0; unsigned long g_CrDbgDumpDraw = 0 #if 0 | CR_SERVER_DUMP_F_COMPILE_SHADER | CR_SERVER_DUMP_F_LINK_PROGRAM #endif ; #if 0 | CR_SERVER_DUMP_F_DRAW_BUFF_ENTER | CR_SERVER_DUMP_F_DRAW_BUFF_LEAVE | CR_SERVER_DUMP_F_DRAW_PROGRAM_UNIFORMS_ENTER | CR_SERVER_DUMP_F_DRAW_PROGRAM_ATTRIBS_ENTER | CR_SERVER_DUMP_F_DRAW_TEX_ENTER | CR_SERVER_DUMP_F_DRAW_PROGRAM_ENTER | CR_SERVER_DUMP_F_DRAW_STATE_ENTER | CR_SERVER_DUMP_F_SWAPBUFFERS_ENTER | CR_SERVER_DUMP_F_DRAWEL | CR_SERVER_DUMP_F_SHADER_SOURCE ; #endif unsigned long g_CrDbgDumpDrawFramesSettings = CR_SERVER_DUMP_F_DRAW_BUFF_ENTER | CR_SERVER_DUMP_F_DRAW_BUFF_LEAVE | CR_SERVER_DUMP_F_DRAW_TEX_ENTER | CR_SERVER_DUMP_F_DRAW_PROGRAM_ENTER | CR_SERVER_DUMP_F_COMPILE_SHADER | CR_SERVER_DUMP_F_LINK_PROGRAM | CR_SERVER_DUMP_F_SWAPBUFFERS_ENTER; unsigned long g_CrDbgDumpDrawFramesAppliedSettings = 0; unsigned long g_CrDbgDumpDrawFramesSavedInitSettings = 0; unsigned long g_CrDbgDumpDrawFramesCount = 0; uint32_t g_CrDbgDumpDrawCount = 0; uint32_t g_CrDbgDumpDumpOnCount = 10; uint32_t g_CrDbgDumpDumpOnCountEnabled = 0; uint32_t g_CrDbgDumpDumpOnCountPerform = 0; uint32_t g_CrDbgDumpDrawFlags = CR_SERVER_DUMP_F_COMPILE_SHADER | CR_SERVER_DUMP_F_SHADER_SOURCE | CR_SERVER_DUMP_F_COMPILE_SHADER | CR_SERVER_DUMP_F_LINK_PROGRAM | CR_SERVER_DUMP_F_DRAW_BUFF_ENTER | CR_SERVER_DUMP_F_DRAW_BUFF_LEAVE | CR_SERVER_DUMP_F_DRAW_TEX_ENTER | CR_SERVER_DUMP_F_DRAW_PROGRAM_UNIFORMS_ENTER | CR_SERVER_DUMP_F_DRAW_PROGRAM_ATTRIBS_ENTER | CR_SERVER_DUMP_F_DRAW_PROGRAM_ENTER | CR_SERVER_DUMP_F_DRAW_STATE_ENTER | CR_SERVER_DUMP_F_SWAPBUFFERS_ENTER | CR_SERVER_DUMP_F_DRAWEL | CR_SERVER_DUMP_F_TEXPRESENT; void crServerDumpCheckTerm() { if (!CrBltIsInitialized(&cr_server.RecorderBlitter)) return; CrBltTerm(&cr_server.RecorderBlitter); } int crServerDumpCheckInit() { int rc; CR_BLITTER_WINDOW BltWin; CR_BLITTER_CONTEXT BltCtx; CRMuralInfo *pBlitterMural; if (!CrBltIsInitialized(&cr_server.RecorderBlitter)) { pBlitterMural = crServerGetDummyMural(cr_server.MainContextInfo.CreateInfo.realVisualBits); if (!pBlitterMural) { crWarning("crServerGetDummyMural failed"); return VERR_GENERAL_FAILURE; } crServerVBoxBlitterWinInit(&BltWin, pBlitterMural); crServerVBoxBlitterCtxInit(&BltCtx, &cr_server.MainContextInfo); rc = CrBltInit(&cr_server.RecorderBlitter, &BltCtx, true, true, NULL, &cr_server.TmpCtxDispatch); if (!RT_SUCCESS(rc)) { crWarning("CrBltInit failed rc %d", rc); return rc; } rc = CrBltMuralSetCurrentInfo(&cr_server.RecorderBlitter, &BltWin); if (!RT_SUCCESS(rc)) { crWarning("CrBltMuralSetCurrentInfo failed rc %d", rc); return rc; } } #if 0 crDmpDbgPrintInit(&cr_server.DbgPrintDumper); cr_server.pDumper = &cr_server.DbgPrintDumper.Base; #else if (!crDmpHtmlIsInited(&cr_server.HtmlDumper)) { static int cCounter = 0; // crDmpHtmlInit(&cr_server.HtmlDumper, "S:\\projects\\virtualbox\\3d\\dumps\\1", "index.html"); crDmpHtmlInitF(&cr_server.HtmlDumper, "/Users/oracle-mac/vbox/dump/1", "index%d.html", cCounter); cr_server.pDumper = &cr_server.HtmlDumper.Base; ++cCounter; } #endif crRecInit(&cr_server.Recorder, &cr_server.RecorderBlitter, &cr_server.TmpCtxDispatch, cr_server.pDumper); return VINF_SUCCESS; } void crServerDumpShader(GLint id) { CRContext *ctx = crStateGetCurrent(); crRecDumpShader(&cr_server.Recorder, ctx, id, 0); } void crServerDumpProgram(GLint id) { CRContext *ctx = crStateGetCurrent(); crRecDumpProgram(&cr_server.Recorder, ctx, id, 0); } void crServerDumpCurrentProgram() { CRContext *ctx = crStateGetCurrent(); crRecDumpCurrentProgram(&cr_server.Recorder, ctx); } void crServerDumpRecompileDumpCurrentProgram() { crDmpStrF(cr_server.Recorder.pDumper, "==Dump(1)=="); crServerRecompileCurrentProgram(); crServerDumpCurrentProgramUniforms(); crServerDumpCurrentProgramAttribs(); crDmpStrF(cr_server.Recorder.pDumper, "Done Dump(1)"); crServerRecompileCurrentProgram(); crDmpStrF(cr_server.Recorder.pDumper, "Dump(2)"); crServerRecompileCurrentProgram(); crServerDumpCurrentProgramUniforms(); crServerDumpCurrentProgramAttribs(); crDmpStrF(cr_server.Recorder.pDumper, "Done Dump(2)"); } void crServerRecompileCurrentProgram() { CRContext *ctx = crStateGetCurrent(); crRecRecompileCurrentProgram(&cr_server.Recorder, ctx); } void crServerDumpCurrentProgramUniforms() { CRContext *ctx = crStateGetCurrent(); crDmpStrF(cr_server.Recorder.pDumper, "==Uniforms=="); crRecDumpCurrentProgramUniforms(&cr_server.Recorder, ctx); crDmpStrF(cr_server.Recorder.pDumper, "==Done Uniforms=="); } void crServerDumpCurrentProgramAttribs() { CRContext *ctx = crStateGetCurrent(); crDmpStrF(cr_server.Recorder.pDumper, "==Attribs=="); crRecDumpCurrentProgramAttribs(&cr_server.Recorder, ctx); crDmpStrF(cr_server.Recorder.pDumper, "==Done Attribs=="); } void crServerDumpState() { CRContext *ctx = crStateGetCurrent(); crRecDumpGlGetState(&cr_server.Recorder, ctx); crRecDumpGlEnableState(&cr_server.Recorder, ctx); } void crServerDumpDrawel(const char*pszFormat, ...) { CRContext *ctx = crStateGetCurrent(); va_list pArgList; va_start(pArgList, pszFormat); crRecDumpVertAttrV(&cr_server.Recorder, ctx, pszFormat, pArgList); va_end(pArgList); } void crServerDumpDrawelv(GLuint idx, const char*pszElFormat, uint32_t cbEl, const void *pvVal, uint32_t cVal) { CRContext *ctx = crStateGetCurrent(); crRecDumpVertAttrv(&cr_server.Recorder, ctx, idx, pszElFormat, cbEl, pvVal, cVal); } void crServerDumpBuffer(int idx) { CRContextInfo *pCtxInfo = cr_server.currentCtxInfo; CRContext *ctx = crStateGetCurrent(); GLint idFBO; GLint idTex; VBOXVR_TEXTURE RedirTex; int rc = crServerDumpCheckInit(); idx = idx >= 0 ? idx : crServerMuralFBOIdxFromBufferName(cr_server.currentMural, pCtxInfo->pContext->buffer.drawBuffer); if (!RT_SUCCESS(rc)) { crWarning("crServerDumpCheckInit failed, rc %d", rc); return; } if (idx < 0) { crWarning("neg idx, unsupported"); return; } idFBO = CR_SERVER_FBO_FOR_IDX(cr_server.currentMural, idx); idTex = CR_SERVER_FBO_TEX_FOR_IDX(cr_server.currentMural, idx); RedirTex.width = cr_server.currentMural->fboWidth; RedirTex.height = cr_server.currentMural->fboHeight; RedirTex.target = GL_TEXTURE_2D; RedirTex.hwid = idTex; crRecDumpBuffer(&cr_server.Recorder, ctx, idFBO, idTex ? &RedirTex : NULL); } void crServerDumpTexture(const VBOXVR_TEXTURE *pTex) { CRContextInfo *pCtxInfo = cr_server.currentCtxInfo; CR_BLITTER_WINDOW BltWin; CR_BLITTER_CONTEXT BltCtx; CRContext *ctx = crStateGetCurrent(); int rc = crServerDumpCheckInit(); if (!RT_SUCCESS(rc)) { crWarning("crServerDumpCheckInit failed, rc %d", rc); return; } crServerVBoxBlitterWinInit(&BltWin, cr_server.currentMural); crServerVBoxBlitterCtxInit(&BltCtx, pCtxInfo); crRecDumpTextureF(&cr_server.Recorder, pTex, &BltCtx, &BltWin, "Tex (%d x %d), hwid (%d) target %#x", pTex->width, pTex->height, pTex->hwid, pTex->target); } void crServerDumpTextures() { CRContextInfo *pCtxInfo = cr_server.currentCtxInfo; CRContext *ctx = crStateGetCurrent(); int rc = crServerDumpCheckInit(); if (!RT_SUCCESS(rc)) { crWarning("crServerDumpCheckInit failed, rc %d", rc); return; } crRecDumpTextures(&cr_server.Recorder, ctx); } void crServerDumpFilterOpLeave(unsigned long event, CR_DUMPER *pDumper) { if (CR_SERVER_DUMP_F_DRAW_LEAVE_ALL & event) { g_CrDbgDumpDumpOnCountPerform = 0; } } bool crServerDumpFilterOpEnter(unsigned long event, CR_DUMPER *pDumper) { if ((CR_SERVER_DUMP_F_SWAPBUFFERS_ENTER & event) || (CR_SERVER_DUMP_F_TEXPRESENT & event)) { if (g_CrDbgDumpDumpOnCountEnabled == 1) g_CrDbgDumpDumpOnCountEnabled = 2; else if (g_CrDbgDumpDumpOnCountEnabled) { g_CrDbgDumpDumpOnCountEnabled = 0; if (cr_server.pDumper == &cr_server.HtmlDumper.Base) { crDmpHtmlTerm(&cr_server.HtmlDumper); cr_server.pDumper = NULL; } } g_CrDbgDumpDrawCount = 0; } else if (CR_SERVER_DUMP_F_DRAW_ENTER_ALL & event) { if (g_CrDbgDumpDumpOnCountEnabled == 2) { if (g_CrDbgDumpDumpOnCount == g_CrDbgDumpDrawCount) { g_CrDbgDumpDumpOnCountPerform = 1; } ++g_CrDbgDumpDrawCount; } } if (g_CrDbgDumpDumpOnCountPerform) { if (g_CrDbgDumpDrawFlags & event) return true; } return CR_SERVER_DUMP_DEFAULT_FILTER_OP(event); } bool crServerDumpFilterDmp(unsigned long event, CR_DUMPER *pDumper) { if (g_CrDbgDumpDumpOnCountPerform) { if (g_CrDbgDumpDrawFlags & event) return true; } return CR_SERVER_DUMP_DEFAULT_FILTER_DMP(event); } void crServerDumpFramesCheck() { if (!g_CrDbgDumpDrawFramesCount) return; if (!g_CrDbgDumpDrawFramesAppliedSettings) { if (!g_CrDbgDumpDrawFramesSettings) { crWarning("g_CrDbgDumpDrawFramesSettings is NULL, bump will not be started"); g_CrDbgDumpDrawFramesCount = 0; return; } g_CrDbgDumpDrawFramesSavedInitSettings = g_CrDbgDumpDraw; g_CrDbgDumpDrawFramesAppliedSettings = g_CrDbgDumpDrawFramesSettings; g_CrDbgDumpDraw = g_CrDbgDumpDrawFramesSettings; crDmpStrF(cr_server.Recorder.pDumper, "***Starting draw dump for %d frames, settings(0x%x)", g_CrDbgDumpDrawFramesCount, g_CrDbgDumpDraw); return; } --g_CrDbgDumpDrawFramesCount; if (!g_CrDbgDumpDrawFramesCount) { crDmpStrF(cr_server.Recorder.pDumper, "***Stop draw dump"); g_CrDbgDumpDraw = g_CrDbgDumpDrawFramesSavedInitSettings; g_CrDbgDumpDrawFramesAppliedSettings = 0; } } #endif GLvoid crServerSpriteCoordReplEnable(GLboolean fEnable) { CRContext *g = crStateGetCurrent(); CRTextureState *t = &(g->texture); GLuint curTextureUnit = t->curTextureUnit; GLuint curTextureUnitRestore = curTextureUnit; GLuint i; for (i = 0; i < g->limits.maxTextureUnits; ++i) { if (g->point.coordReplacement[i]) { if (i != curTextureUnit) { curTextureUnit = i; cr_server.head_spu->dispatch_table.ActiveTextureARB( i + GL_TEXTURE0_ARB ); } cr_server.head_spu->dispatch_table.TexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, (GLint)fEnable); } } if (curTextureUnit != curTextureUnitRestore) { cr_server.head_spu->dispatch_table.ActiveTextureARB( curTextureUnitRestore + GL_TEXTURE0_ARB ); } } GLvoid SERVER_DISPATCH_APIENTRY crServerDispatchDrawArrays(GLenum mode, GLint first, GLsizei count) { #ifdef DEBUG GLenum status = cr_server.head_spu->dispatch_table.CheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT); Assert(GL_FRAMEBUFFER_COMPLETE == status); #endif if (mode == GL_POINTS) crServerSpriteCoordReplEnable(GL_TRUE); CR_SERVER_DUMP_DRAW_ENTER(); CR_GLERR_CHECK(cr_server.head_spu->dispatch_table.DrawArrays(mode, first, count);); CR_SERVER_DUMP_DRAW_LEAVE(); if (mode == GL_POINTS) crServerSpriteCoordReplEnable(GL_FALSE); } GLvoid SERVER_DISPATCH_APIENTRY crServerDispatchDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid * indices) { #ifdef DEBUG GLenum status = cr_server.head_spu->dispatch_table.CheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT); Assert(GL_FRAMEBUFFER_COMPLETE == status); #endif if (mode == GL_POINTS) crServerSpriteCoordReplEnable(GL_TRUE); CR_SERVER_DUMP_DRAW_ENTER(); CR_GLERR_CHECK(cr_server.head_spu->dispatch_table.DrawElements(mode, count, type, indices);); CR_SERVER_DUMP_DRAW_LEAVE(); if (mode == GL_POINTS) crServerSpriteCoordReplEnable(GL_FALSE); } void SERVER_DISPATCH_APIENTRY crServerDispatchEnd( void ) { CRContext *g = crStateGetCurrent(); GLenum mode = g->current.mode; crStateEnd(); cr_server.head_spu->dispatch_table.End(); CR_SERVER_DUMP_DRAW_LEAVE(); if (mode == GL_POINTS) crServerSpriteCoordReplEnable(GL_FALSE); } void SERVER_DISPATCH_APIENTRY crServerDispatchBegin(GLenum mode) { #ifdef DEBUG CRContext *ctx = crStateGetCurrent(); SPUDispatchTable *gl = &cr_server.head_spu->dispatch_table; if (ctx->program.vpProgramBinding) { AssertRelease(ctx->program.currentVertexProgram); if (ctx->program.currentVertexProgram->isARBprogram) { GLint pid=-1; gl->GetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_BINDING_ARB, &pid); if (pid != ctx->program.currentVertexProgram->id) { crWarning("pid(%d) != ctx->program.currentVertexProgram->id(%d)", pid, ctx->program.currentVertexProgram->id); } AssertRelease(pid == ctx->program.currentVertexProgram->id); } else { GLint pid=-1; gl->GetIntegerv(GL_VERTEX_PROGRAM_BINDING_NV, &pid); if (pid != ctx->program.currentVertexProgram->id) { crWarning("pid(%d) != ctx->program.currentVertexProgram->id(%d)", pid, ctx->program.currentVertexProgram->id); } AssertRelease(pid == ctx->program.currentVertexProgram->id); } } else if (ctx->glsl.activeProgram) { GLint pid=-1; gl->GetIntegerv(GL_CURRENT_PROGRAM, &pid); //crDebug("pid %i, state: id %i, hwid %i", pid, ctx->glsl.activeProgram->id, ctx->glsl.activeProgram->hwid); if (pid != ctx->glsl.activeProgram->hwid) { crWarning("pid(%d) != ctx->glsl.activeProgram->hwid(%d)", pid, ctx->glsl.activeProgram->hwid); } AssertRelease(pid == ctx->glsl.activeProgram->hwid); } #endif if (mode == GL_POINTS) crServerSpriteCoordReplEnable(GL_TRUE); CR_SERVER_DUMP_DRAW_ENTER(); crStateBegin(mode); cr_server.head_spu->dispatch_table.Begin(mode); }