PsychError SCREENSetOpenGLTexture(void) { PsychWindowRecordType *windowRecord, *textureRecord; int texid, w, h, d, testarg, textureShader, usefloatformat = 0; int specialFlags = 0; GLenum target = 0; texid=w=h=d=-1; //all subfunctions should have these two lines. PsychPushHelp(useString, synopsisString, seeAlsoString); if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);}; PsychErrorExit(PsychCapNumInputArgs(9)); //The maximum number of inputs PsychErrorExit(PsychRequireNumInputArgs(4)); //The required number of inputs PsychErrorExit(PsychCapNumOutputArgs(2)); //The maximum number of outputs // Get the window record from the window record argument and get info from the window record PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord); // Get the texture record from the texture record argument. // Check if either none ( [] or '' ) or the special value zero was // provided as Psychtoolbox textureHandle. In that case, we create a new // empty texture record instead of reusing an existing one. testarg=0; PsychCopyInIntegerArg(2, FALSE, &testarg); if (testarg==0) { // No valid textureHandle provided. Create a new empty textureRecord. PsychCreateWindowRecord(&textureRecord); textureRecord->windowType=kPsychTexture; textureRecord->screenNumber = windowRecord->screenNumber; // Assign parent window and copy its inheritable properties: PsychAssignParentWindow(textureRecord, windowRecord); // Mark it valid and return handle to userspace: PsychSetWindowRecordValid(textureRecord); } else { // None of the special values provided. We assume its a handle to a valid // and existing PTB texture and try to retrieve the textureRecord: PsychAllocInWindowRecordArg(2, TRUE, &textureRecord); } // Is it a textureRecord? if (!PsychIsTexture(textureRecord)) { PsychErrorExitMsg(PsychError_user, "You tried to set texture information on something else than a texture!"); } // Query OpenGL texid: PsychCopyInIntegerArg(3, TRUE, &texid); // Query OpenGL texture target: PsychCopyInIntegerArg(4, TRUE, (int*) &target); // Query optional override width: PsychCopyInIntegerArg(5, FALSE, &w); // Query optional override height: PsychCopyInIntegerArg(6, FALSE, &h); // Query optional override depth: PsychCopyInIntegerArg(7, FALSE, &d); // Get optional texture shader handle: textureShader = 0; PsychCopyInIntegerArg(8, FALSE, &textureShader); // Get optional specialFlags: PsychCopyInIntegerArg(9, FALSE, &specialFlags); // Activate OpenGL rendering context of windowRecord: PsychSetGLContext(windowRecord); // Bind the provided external OpenGL texture object: PsychTestForGLErrors(); glBindTexture(target, texid); PsychTestForGLErrors(); // Binding worked. Query its size and format unless override values are given: if (w==-1) glGetTexLevelParameteriv(target, 0, GL_TEXTURE_WIDTH, (GLint*) &w); if (h==-1) glGetTexLevelParameteriv(target, 0, GL_TEXTURE_HEIGHT, (GLint*) &h); if (d==-1) glGetTexLevelParameteriv(target, 0, GL_TEXTURE_DEPTH, (GLint*) &d); if (w<=0) { PsychErrorExitMsg(PsychError_user, "You tried to set invalid (negative) texture width."); } if (h<=0) { PsychErrorExitMsg(PsychError_user, "You tried to set invalid (negative) texture height."); } if (d<=0) { PsychErrorExitMsg(PsychError_user, "You tried to set invalid (negative) texture depth."); } // Ok, setup texture record for texture: PsychInitWindowRecordTextureFields(textureRecord); textureRecord->depth = d; // Assume this texture has four channels. FIXME: Is this problematic? textureRecord->nrchannels = 4; PsychMakeRect(textureRecord->rect, 0, 0, w, h); // Client rect of a texture is always == rect of it: PsychCopyRect(textureRecord->clientrect, textureRecord->rect); textureRecord->texturetarget = target; // Orientation is set to 2 - like an upright Offscreen window texture: textureRecord->textureOrientation = 2; textureRecord->textureNumber = texid; // Assign GLSL filter-/lookup-shaders if needed: usefloatformat is determined // by query, whereas the 'userRequest' flag is set to zero for now. glGetTexLevelParameteriv(target, 0, GL_TEXTURE_RED_SIZE, (GLint*) &d); if (d <= 0) glGetTexLevelParameteriv(target, 0, GL_TEXTURE_LUMINANCE_SIZE, (GLint*) &d); if (d < 16) usefloatformat = 0; if (d >= 16) usefloatformat = 1; if (d >= 32) usefloatformat = 2; // Assign bpc value: textureRecord->bpc = (int) d; PsychAssignHighPrecisionTextureShaders(textureRecord, windowRecord, usefloatformat, (specialFlags & 2) ? 1 : 0); // specialFlags setting 8? Disable auto-mipmap generation: if (specialFlags & 0x8) textureRecord->specialflags |= kPsychDontAutoGenMipMaps; // A specialFlags setting of 32? Protect texture against deletion via Screen('Close') without providing a explicit handle: if (specialFlags & 32) textureRecord->specialflags |= kPsychDontDeleteOnClose; // User specified override shader for this texture provided? This is useful for // basic image processing and procedural texture shading: if (textureShader!=0) { // Assign provided shader as filtershader to this texture: We negate it so // that the texture blitter routines know this is a custom shader, not our // built in filter shader: textureRecord->textureFilterShader = -1 * textureShader; } // Unbind texture: glBindTexture(target, 0); // printf("id %i target: %i w %i h %i", texid, target, w, h); // Return new (or old) PTB textureHandle for this texture: PsychCopyOutDoubleArg(1, FALSE, textureRecord->windowIndex); PsychCopyOutRectArg(2, FALSE, textureRecord->rect); // Done. return(PsychError_none); }
PsychError SCREENSetOpenGLTextureFromMemPointer(void) { PsychWindowRecordType *windowRecord, *textureRecord; int w, h, d, testarg, upsidedown, glinternalformat, glexternaltype, glexternalformat; double doubleMemPtr; GLenum target = 0; w=h=d=-1; doubleMemPtr = 0; upsidedown = 0; //all subfunctions should have these two lines. PsychPushHelp(useString, synopsisString, seeAlsoString); if(PsychIsGiveHelp()){PsychGiveHelp();return(PsychError_none);}; PsychErrorExit(PsychCapNumInputArgs(11)); // The maximum number of inputs PsychErrorExit(PsychRequireNumInputArgs(5)); // The required number of inputs PsychErrorExit(PsychCapNumOutputArgs(2)); // The maximum number of outputs // Get the window record from the window record argument and get info from the window record PsychAllocInWindowRecordArg(kPsychUseDefaultArgPosition, TRUE, &windowRecord); // Get the texture record from the texture record argument. // Check if either none ( [] or '' ) or the special value zero was // provided as Psychtoolbox textureHandle. In that case, we create a new // empty texture record instead of reusing an existing one. testarg=0; PsychCopyInIntegerArg(2, FALSE, &testarg); if (testarg==0) { // No valid textureHandle provided. Create a new empty textureRecord. PsychCreateWindowRecord(&textureRecord); textureRecord->windowType=kPsychTexture; textureRecord->screenNumber = windowRecord->screenNumber; textureRecord->targetSpecific.contextObject = windowRecord->targetSpecific.contextObject; textureRecord->targetSpecific.deviceContext = windowRecord->targetSpecific.deviceContext; textureRecord->targetSpecific.glusercontextObject = windowRecord->targetSpecific.glusercontextObject; textureRecord->colorRange = windowRecord->colorRange; // Copy imaging mode flags from parent: textureRecord->imagingMode = windowRecord->imagingMode; // Mark it valid and return handle to userspace: PsychSetWindowRecordValid(textureRecord); } else { // None of the special values provided. We assume its a handle to a valid // and existing PTB texture and try to retrieve the textureRecord: PsychAllocInWindowRecordArg(2, TRUE, &textureRecord); } // Is it a textureRecord? if (!PsychIsTexture(textureRecord)) { PsychErrorExitMsg(PsychError_user, "You tried to set texture information on something else than a texture!"); } // Query double-encoded memory pointer: PsychCopyInDoubleArg(3, TRUE, &doubleMemPtr); // Query width: PsychCopyInIntegerArg(4, TRUE, &w); // Query height: PsychCopyInIntegerArg(5, TRUE, &h); // Query depth: PsychCopyInIntegerArg(6, TRUE, &d); // Query (optional) upsidedown - flag: PsychCopyInIntegerArg(7, FALSE, &upsidedown); // Query (optional) OpenGL texture target: PsychCopyInIntegerArg(8, FALSE, (int*) &target); // Query (optional) full format spec: glinternalformat = 0; PsychCopyInIntegerArg(9, FALSE, &glinternalformat); if (glinternalformat>0) { // Ok copy the (now non-optional) remaining format spec: PsychCopyInIntegerArg(10, TRUE, &glexternalformat); PsychCopyInIntegerArg(11, TRUE, &glexternaltype); } // Safety checks: if (doubleMemPtr == 0) { PsychErrorExitMsg(PsychError_user, "You tried to set invalid (NULL) imagePtr."); } if (w<=0) { PsychErrorExitMsg(PsychError_user, "You tried to set invalid (negative) texture width."); } if (h<=0) { PsychErrorExitMsg(PsychError_user, "You tried to set invalid (negative) texture height."); } if (d<=0) { PsychErrorExitMsg(PsychError_user, "You tried to set invalid (negative) texture depth."); } if (d>4) { PsychErrorExitMsg(PsychError_user, "You tried to set invalid (greater than four) texture depth."); } if (target!=0 && target!=GL_TEXTURE_RECTANGLE_EXT && target!=GL_TEXTURE_2D) { PsychErrorExitMsg(PsychError_user, "You tried to set invalid texture target."); } // Activate OpenGL rendering context of windowRecord and make it the active drawing target: PsychSetGLContext(windowRecord); PsychSetDrawingTarget(windowRecord); PsychTestForGLErrors(); // Ok, setup texture record for texture: PsychInitWindowRecordTextureFields(textureRecord); textureRecord->depth = d * 8; textureRecord->nrchannels = d; PsychMakeRect(textureRecord->rect, 0, 0, w, h); // Override texture target, if one was provided: if (target!=0) textureRecord->texturetarget = target; // Orientation is normally set to 2 - like an upright Offscreen window texture. // If upsidedown flag is set, then we do 3 - an upside down Offscreen window texture. textureRecord->textureOrientation = (upsidedown>0) ? 3 : 2; if (glinternalformat!=0) { textureRecord->textureinternalformat = glinternalformat; textureRecord->textureexternalformat = glexternalformat; textureRecord->textureexternaltype = glexternaltype; } // Setting memsize to zero prevents unwanted free() operation in PsychDeleteTexture... textureRecord->textureMemorySizeBytes = 0; // This will retrieve an OpenGL compatible pointer to the raw pixel data and assign it to our texmemptr: textureRecord->textureMemory = (GLuint*) PsychDoubleToPtr(doubleMemPtr); // printf("InTexPtr %p , %.20e", PsychDoubleToPtr(doubleMemPtr), doubleMemPtr); // Let PsychCreateTexture() do the rest of the job of creating, setting up and // filling an OpenGL texture with memory buffers image content: PsychCreateTexture(textureRecord); // Return new (or old) PTB textureHandle for this texture: PsychCopyOutDoubleArg(1, FALSE, textureRecord->windowIndex); PsychCopyOutRectArg(2, FALSE, textureRecord->rect); // Done. return(PsychError_none); }
PsychError SCREENTransformTexture(void) { PsychWindowRecordType *sourceRecord, *targetRecord, *proxyRecord, *sourceRecord2; int testarg, specialFlags, usefloatformat, d; // All subfunctions should have these two lines. PsychPushHelp(useString, synopsisString, seeAlsoString); if (PsychIsGiveHelp()) { PsychGiveHelp(); return(PsychError_none); }; PsychErrorExit(PsychCapNumInputArgs(5)); PsychErrorExit(PsychRequireNumInputArgs(2)); PsychErrorExit(PsychCapNumOutputArgs(1)); // OpenGL FBO's supported? Otherwise this is a no-go... if (glBindFramebufferEXT == NULL || glUseProgram == NULL) { // Game over! printf("PTB-ERROR: Sorry, your graphics driver & hardware does not support the required OpenGL framebuffer object extension or\n"); printf("PTB-ERROR: the OpenGL shading language for hardware accelerated fragment processing. This function is therefore disabled.\n"); printf("PTB-ERROR: You will need at least a NVidia GeforceFX-5200, a ATI Radeon 9600 or a Intel GMA-950 graphics card for this\n"); printf("PTB-ERROR: to work. If you have such a card (or a more recent one) then you'll need to update your graphics drivers.\n\n"); PsychErrorExitMsg(PsychError_user, "Screen('TransformTexture') command unsupported on your combination of graphics hardware & driver."); } // Get the window structure for the source texture. PsychAllocInWindowRecordArg(1, TRUE, &sourceRecord); if (!PsychIsTexture(sourceRecord)) PsychErrorExitMsg(PsychError_user, "'sourceTexture' argument must be a handle to a texture or offscreen window."); // Get the window structure for the proxy object. PsychAllocInWindowRecordArg(2, TRUE, &proxyRecord); if (proxyRecord->windowType != kPsychProxyWindow) PsychErrorExitMsg(PsychError_user, "'transformProxyPtr' argument must be a handle to a proxy object."); // Test if optional specialFlags are provided: specialFlags = 0; PsychCopyInIntegerArg(5, FALSE, &specialFlags); // Activate rendering context of the proxy object and soft-reset the drawing engine, // so we're in a well defined state. The value 1 means: Reset safely, ie. do any // framebuffer backups that might be needed before NULL-ing the binding: PsychSetDrawingTarget((PsychWindowRecordType*) 0x1); PsychSetGLContext(proxyRecord); // Save all state: glPushAttrib(GL_ALL_ATTRIB_BITS); // Disable alpha-blending: glDisable(GL_BLEND); // Reset color write mask to "all enabled" glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE); // Disable any shaders: PsychSetShader(proxyRecord, 0); // Transform sourceRecord source texture into a normalized, upright texture if it isn't already in // that format. We require this standard orientation for simplified shader design. if (!(specialFlags & 1)) PsychNormalizeTextureOrientation(sourceRecord); // Test if optional 2nd source texture is provided: testarg = 0; PsychCopyInIntegerArg(3, FALSE, &testarg); if (testarg != 0) { // Tes. Get the window structure for the 2nd source texture. PsychAllocInWindowRecordArg(3, TRUE, &sourceRecord2); if (!PsychIsTexture(sourceRecord2)) PsychErrorExitMsg(PsychError_user, "'sourceTexture2' argument must be a handle to a texture or offscreen window."); // Transform sourceRecord2 source texture into a normalized, upright texture if it isn't already in // that format. We require this standard orientation for simplified shader design. if (!(specialFlags & 1)) PsychNormalizeTextureOrientation(sourceRecord2); } else { // No secondary source texture: sourceRecord2 = NULL; } // Restore proper rendering context: PsychSetGLContext(proxyRecord); // Test if optional target texture is provided: testarg = 0; PsychCopyInIntegerArg(4, FALSE, &testarg); // Do we need to create a new one from scratch? if (testarg == 0) { // No valid textureHandle provided. Create a new empty textureRecord which clones some // of the properties of the sourceRecord targetRecord = NULL; PsychCreateWindowRecord(&targetRecord); PsychInitWindowRecordTextureFields(targetRecord); targetRecord->windowType=kPsychTexture; targetRecord->screenNumber = sourceRecord->screenNumber; // Assign parent window and copy its inheritable properties: PsychAssignParentWindow(targetRecord, sourceRecord); targetRecord->depth = sourceRecord->depth; // Assume this texture has four channels. targetRecord->nrchannels = 4; PsychCopyRect(targetRecord->rect, sourceRecord->rect); PsychCopyRect(targetRecord->clientrect, targetRecord->rect); targetRecord->texturetarget = sourceRecord->texturetarget; // Orientation is set to 2 - like an upright Offscreen window texture: targetRecord->textureOrientation = 2; // Mark it valid and return handle to userspace: PsychSetWindowRecordValid(targetRecord); } else { // Get the window structure for the target texture. PsychAllocInWindowRecordArg(4, TRUE, &targetRecord); if (!PsychIsTexture(targetRecord)) PsychErrorExitMsg(PsychError_user, "'targetTexture' argument must be a handle to a texture or offscreen window."); } // Make sure our source textures have at least a pseudo FBO for read-access: PsychCreateShadowFBOForTexture(sourceRecord, FALSE, -1); if (sourceRecord2) PsychCreateShadowFBOForTexture(sourceRecord2, FALSE, -1); // Make sure the target texture is upright/normalized: if (!(specialFlags & 1)) PsychNormalizeTextureOrientation(targetRecord); // Make sure our target texture has a full-blown FBO attached as a rendertarget. // As our proxy object defines the image processing ops, it also defines the // required imagingMode properties for the target texture: PsychCreateShadowFBOForTexture(targetRecord, TRUE, proxyRecord->imagingMode); // Assign GLSL filter-/lookup-shaders if needed: usefloatformat is queried. // The 'userRequest' flag is set depending on specialFlags setting & 2. glBindTexture(targetRecord->texturetarget, targetRecord->textureNumber); glGetTexLevelParameteriv(targetRecord->texturetarget, 0, GL_TEXTURE_RED_SIZE, (GLint*) &d); if (d <= 0) glGetTexLevelParameteriv(targetRecord->texturetarget, 0, GL_TEXTURE_LUMINANCE_SIZE, (GLint*) &d); glBindTexture(targetRecord->texturetarget, 0); usefloatformat = 0; if (d == 16) usefloatformat = 1; if (d >= 32) usefloatformat = 2; PsychAssignHighPrecisionTextureShaders(targetRecord, sourceRecord, usefloatformat, (specialFlags & 2) ? 1 : 0); // Make sure our proxy has suitable bounce buffers if we need any: if (proxyRecord->imagingMode & (kPsychNeedDualPass | kPsychNeedMultiPass)) { // Needs multi-pass processing. Create bounce buffer if neccessary: PsychCopyRect(proxyRecord->rect, targetRecord->rect); PsychCopyRect(proxyRecord->clientrect, targetRecord->rect); // Build FBO for bounce-buffering. This will always be upright/normalized, // so no need to normalize "texture orientation" for proxyRecord bounce buffers: PsychCreateShadowFBOForTexture(proxyRecord, TRUE, proxyRecord->imagingMode); } // Make sure we don't have VRAM memory feedback loops: if ((sourceRecord->textureNumber == targetRecord->textureNumber) || (sourceRecord2 && (sourceRecord2->textureNumber == targetRecord->textureNumber))) PsychErrorExitMsg(PsychError_user, "Source texture and target texture must be different!"); // Apply image processing operation: Use ressources and OpenGL context of proxyRecord, run user defined blit chain, // Don't supply user specific data (NULL), don't supply override blitter (NULL), source is read-only (TRUE), no // swizzle allowed (FALSE), sourceRecord is source, targetRecord is destination, bounce buffers provided by proxyRecord, // no secondary FBO available (NULL). PsychPipelineExecuteHook(proxyRecord, kPsychUserDefinedBlit, NULL, NULL, TRUE, FALSE, &(sourceRecord->fboTable[sourceRecord->drawBufferFBO[0]]), (sourceRecord2) ? &(sourceRecord2->fboTable[sourceRecord2->drawBufferFBO[0]]) : NULL, &(targetRecord->fboTable[targetRecord->drawBufferFBO[0]]), (proxyRecord->drawBufferFBO[0]!=-1) ? &(proxyRecord->fboTable[proxyRecord->drawBufferFBO[0]]) : NULL); // Restore previous settings: glPopAttrib(); // Set "dirty" flag on texture: (Ab)used to trigger regeneration of mip-maps during texture drawing of mip-mapped textures. targetRecord->needsViewportSetup = TRUE; //Return the window index and the rect argument. PsychCopyOutDoubleArg(1, FALSE, targetRecord->windowIndex); // Done. return(PsychError_none); }