diff --git a/public/togl/cglmtex.h b/public/togl/cglmtex.h index 4c6d81210..a18cfb602 100644 --- a/public/togl/cglmtex.h +++ b/public/togl/cglmtex.h @@ -104,6 +104,7 @@ enum EGLMTexFlags kGLMTexMultisampled = 0x40, // has an RBO backing it. Cannot combine with Mipped, MippedAuto. One slice maximum, only targeting GL_TEXTURE_2D. // actually not 100% positive on the mipmapping, the RBO itself can't be mipped, but the resulting texture could // have mipmaps generated. + kGLMTexDynamic = 0x80 }; //=============================================================================== @@ -452,7 +453,7 @@ class CGLMTex int CalcSliceIndex( int face, int mip ); void CalcTexelDataOffsetAndStrides( int sliceIndex, int x, int y, int z, int *offsetOut, int *yStrideOut, int *zStrideOut ); - void ReadTexels( GLMTexLockDesc *desc, bool readWholeSlice=true ); + GLubyte* ReadTexels( GLMTexLockDesc *desc, bool readWholeSlice=true ); void WriteTexels( GLMTexLockDesc *desc, bool writeWholeSlice=true, bool noDataWrite=false ); // last param lets us send NULL data ptr (only legal with uncompressed formats, beware) // this helps out ResetSRGB. @@ -472,6 +473,9 @@ class CGLMTex // noWrite means send NULL for texel source addresses instead of actual data - ideal for RT's GLuint m_texName; // name of this texture in the context + GLubyte *m_mapped; + GLuint m_pbo; + GLenum m_texGLTarget; uint m_nSamplerType; // SAMPLER_2D, etc. diff --git a/togl/cglmtex.cpp b/togl/cglmtex.cpp index d4eeb84c9..eb60886fb 100644 --- a/togl/cglmtex.cpp +++ b/togl/cglmtex.cpp @@ -737,6 +737,17 @@ CGLMTex::CGLMTex( GLMContext *ctx, GLMTexLayout *layout, uint levels, const char m_pBlitSrcFBO = NULL; m_pBlitDstFBO = NULL; + m_mapped = NULL; + m_pbo = 0; + + if( m_layout->m_key.m_texFlags & kGLMTexDynamic ) + { + gGL->glGenBuffersARB(1, &m_pbo); + gGL->glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, m_pbo); + gGL->glBufferDataARB(GL_PIXEL_UNPACK_BUFFER, m_layout->m_storageTotalSize, 0, GL_STREAM_DRAW); + gGL->glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, 0); + } + // Sense whether to try and apply client storage upon teximage/subimage. // This should only be true if we're running on OSX 10.6 or it was explicitly // enabled with -gl_texclientstorage on the command line. @@ -796,12 +807,11 @@ CGLMTex::CGLMTex( GLMContext *ctx, GLMTexLayout *layout, uint levels, const char // OK, our texture now exists and is bound on the active TMU. Not drawable yet though. - // if not an RT, create backing storage and fill it - if ( !(layout->m_key.m_texFlags & kGLMTexRenderable) ) + // Create backing storage and fill it + if ( !(layout->m_key.m_texFlags & kGLMTexRenderable) && m_texClientStorage ) { m_backing = (char *)malloc( m_layout->m_storageTotalSize ); - memset( m_backing, 0, m_layout->m_storageTotalSize ); - + // track bytes allocated for non-RT's int formindex = sEncodeLayoutAsIndex( &layout->m_key ); @@ -1012,7 +1022,10 @@ CGLMTex::~CGLMTex( ) free( m_debugLabel ); m_debugLabel = NULL; } - + + if( m_pbo ) + gGL->glDeleteBuffersARB( 1, &m_pbo ); + m_ctx = NULL; } @@ -1072,10 +1085,11 @@ void CGLMTex::CalcTexelDataOffsetAndStrides( int sliceIndex, int x, int y, int z *zStrideOut = zStride; } -void CGLMTex::ReadTexels( GLMTexLockDesc *desc, bool readWholeSlice ) +GLubyte *CGLMTex::ReadTexels( GLMTexLockDesc *desc, bool readWholeSlice ) { GLMRegion readBox; - + GLubyte* data = NULL; + if (readWholeSlice) { readBox.xmin = readBox.ymin = readBox.zmin = 0; @@ -1088,7 +1102,7 @@ void CGLMTex::ReadTexels( GLMTexLockDesc *desc, bool readWholeSlice ) { readBox = desc->m_req.m_region; } - + CGLMTex *pPrevTex = m_ctx->m_samplers[0].m_pBoundTex; m_ctx->BindTexToTMU( this, 0 ); // SelectTMU(n) is a side effect @@ -1100,46 +1114,9 @@ void CGLMTex::ReadTexels( GLMTexLockDesc *desc, bool readWholeSlice ) GLMTexFormatDesc *format = m_layout->m_format; GLenum target = m_layout->m_key.m_texGLTarget; - - void *sliceAddress = m_backing + m_layout->m_slices[ desc->m_sliceIndex ].m_storageOffset; // this would change for PBO - //int sliceSize = m_layout->m_slices[ desc->m_sliceIndex ].m_storageSize; - - // interestingly enough, we can use the same path for both 2D and 3D fetch - - switch( target ) - { - case GL_TEXTURE_CUBE_MAP: - // adjust target to steer to the proper face, then fall through to the 2D texture path. - target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + desc->m_req.m_face; - - case GL_TEXTURE_2D: - case GL_TEXTURE_3D: - { - // check compressed or not - if (format->m_chunkSize != 1) - { - // compressed path - // http://www.opengl.org/sdk/docs/man/xhtml/glGetCompressedTexImage.xml - VPROF( "glGetCompressedTexImage" ); - gGL->glGetCompressedTexImage( target, // target - desc->m_req.m_mip, // level - sliceAddress ); // destination - } - else - { - // uncompressed path - // http://www.opengl.org/sdk/docs/man/xhtml/glGetTexImage.xml - VPROF( "glGetTexImage" ); - gGL->glGetTexImage( target, // target - desc->m_req.m_mip, // level - format->m_glDataFormat, // dataformat - format->m_glDataType, // datatype - sliceAddress ); // destination - } - } - break; - } + gGL->glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, m_pbo); + data = (GLubyte*)gGL->glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, m_layout->m_slices[ desc->m_sliceIndex ].m_storageSize, GL_MAP_WRITE_BIT); } else { @@ -1147,6 +1124,8 @@ void CGLMTex::ReadTexels( GLMTexLockDesc *desc, bool readWholeSlice ) } m_ctx->BindTexToTMU( pPrevTex, 0 ); + + return data; } // TexSubImage should work properly on every driver stack and GPU--enabling by default. @@ -1201,8 +1180,14 @@ void CGLMTex::WriteTexels( GLMTexLockDesc *desc, bool writeWholeSlice, bool noDa GLenum glDataFormat = format->m_glDataFormat; // this could change if expansion kicks in GLenum glDataType = format->m_glDataType; - GLMTexLayoutSlice *slice = &m_layout->m_slices[ desc->m_sliceIndex ]; - void *sliceAddress = m_backing ? (m_backing + slice->m_storageOffset) : NULL; // this would change for PBO + GLMTexLayoutSlice *slice = &m_layout->m_slices[ desc->m_sliceIndex ]; + + void *sliceAddress = NULL; + + if( m_mapped ) + sliceAddress = m_mapped; + else if( m_backing ) + sliceAddress = m_backing + slice->m_storageOffset; // allow use of subimage if the target is texture2D and it has already been teximage'd bool mayUseSubImage = false; @@ -1249,7 +1234,7 @@ void CGLMTex::WriteTexels( GLMTexLockDesc *desc, bool writeWholeSlice, bool noDa //gGL->glTexParameteri( target, GL_TEXTURE_BASE_LEVEL, desc->m_req.m_mip); } - if (needsExpand) + if (needsExpand && !m_mapped) { int expandSize = 0; @@ -1329,12 +1314,13 @@ void CGLMTex::WriteTexels( GLMTexLockDesc *desc, bool writeWholeSlice, bool noDa { // go subimage2D if it's a replacement, not a creation + if( !m_mapped ) + { + gGL->glPixelStorei( GL_UNPACK_ROW_LENGTH, slice->m_xSize ); // in pixels + gGL->glPixelStorei( GL_UNPACK_SKIP_PIXELS, writeBox.xmin ); // in pixels + gGL->glPixelStorei( GL_UNPACK_SKIP_ROWS, writeBox.ymin ); // in pixels - gGL->glPixelStorei( GL_UNPACK_ROW_LENGTH, slice->m_xSize ); // in pixels - gGL->glPixelStorei( GL_UNPACK_SKIP_PIXELS, writeBox.xmin ); // in pixels - gGL->glPixelStorei( GL_UNPACK_SKIP_ROWS, writeBox.ymin ); // in pixels - - gGL->glTexSubImage2D( target, + gGL->glTexSubImage2D( target, desc->m_req.m_mip, // level writeBox.xmin, // xoffset into dest writeBox.ymin, // yoffset into dest @@ -1343,25 +1329,25 @@ void CGLMTex::WriteTexels( GLMTexLockDesc *desc, bool writeWholeSlice, bool noDa glDataFormat, // format glDataType, // type sliceAddress // data (will be offsetted by the SKIP_PIXELS and SKIP_ROWS - let GL do the math to find the first source texel) - ); - - gGL->glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 ); - gGL->glPixelStorei( GL_UNPACK_SKIP_PIXELS, 0 ); - gGL->glPixelStorei( GL_UNPACK_SKIP_ROWS, 0 ); - - /* - //http://www.opengl.org/sdk/docs/man/xhtml/glTexSubImage2D.xml - glTexSubImage2D( target, - desc->m_req.m_mip, // level - 0, // xoffset - 0, // yoffset - slice->m_xSize, // width - slice->m_ySize, // height - glDataFormat, // format - glDataType, // type - sliceAddress // data - ); - */ + ); + + gGL->glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 ); + gGL->glPixelStorei( GL_UNPACK_SKIP_PIXELS, 0 ); + gGL->glPixelStorei( GL_UNPACK_SKIP_ROWS, 0 ); + } + else + { + gGL->glTexSubImage2D( target, + desc->m_req.m_mip, // level + writeBox.xmin, // xoffset into dest + writeBox.ymin, // yoffset into dest + writeBox.xmax - writeBox.xmin, // width (was slice->m_xSize) + writeBox.ymax - writeBox.ymin, // height (was slice->m_ySize) + glDataFormat, // format + glDataType, // type + 0 + ); + } } else { @@ -1376,7 +1362,7 @@ void CGLMTex::WriteTexels( GLMTexLockDesc *desc, bool writeWholeSlice, bool noDa } } } - + // uncompressed path // http://www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/gl/teximage2d.html gGL->glTexImage2D( target, // target @@ -1424,8 +1410,6 @@ void CGLMTex::WriteTexels( GLMTexLockDesc *desc, bool writeWholeSlice, bool noDa } else { - // uncompressed path - // http://www.opengl.org/sdk/docs/man/xhtml/glTexImage3D.xml gGL->glTexImage3D( target, // target desc->m_req.m_mip, // level intformat, // internalformat @@ -1592,15 +1576,18 @@ void CGLMTex::Lock( GLMTexLockParams *params, char** addressOut, int* yStrideOut desc->m_sliceRegionOffset = offsetInSlice + desc->m_sliceBaseOffset; - if (copyout) + if ( copyout && (m_layout->m_key.m_texFlags & kGLMTexDynamic) ) { - VPROF( "ReadTexels" ); // read the whole slice // (odds are we'll never request anything but a whole slice to be read..) - ReadTexels( desc, true ); - } // this would be a good place to fill with scrub value if in debug... - - *addressOut = m_backing + desc->m_sliceRegionOffset; + m_mapped = ReadTexels( desc, true ); + *addressOut = (char*)m_mapped; + } + else + { + *addressOut = m_backing + desc->m_sliceRegionOffset; + } + *yStrideOut = yStride; *zStrideOut = zStride; @@ -1686,7 +1673,16 @@ void CGLMTex::Unlock( GLMTexLockParams *params ) // fullyDirty |= (m_sliceFlags[ desc->m_sliceIndex ] & kSliceStorageValid); - WriteTexels( desc, fullyDirty ); + if( m_layout->m_key.m_texFlags & kGLMTexDynamic ) + { + gGL->glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); + + WriteTexels( desc, fullyDirty ); + m_mapped = NULL; + gGL->glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, 0); + } + else + WriteTexels( desc, fullyDirty ); // logical place to trigger preloading // only do it for an RT tex, if it is not yet attached to any FBO. diff --git a/togl/dxabstract.cpp b/togl/dxabstract.cpp index 0d4738a8d..345b32014 100644 --- a/togl/dxabstract.cpp +++ b/togl/dxabstract.cpp @@ -381,7 +381,7 @@ HRESULT IDirect3DDevice9::CreateTexture(UINT Width,UINT Height,UINT Levels,DWORD if (Usage & D3DUSAGE_DYNAMIC) { - // GLMPRINTF(("-X- DYNAMIC tex usage ignored..")); //FIXME + key.m_texFlags |= kGLMTexDynamic; } if (Usage & D3DUSAGE_TEXTURE_SRGB) @@ -594,7 +594,7 @@ HRESULT IDirect3DDevice9::CreateCubeTexture(UINT EdgeLength,UINT Levels,DWORD Us if (Usage & D3DUSAGE_DYNAMIC) { - //GLMPRINTF(("-X- DYNAMIC tex usage ignored..")); //FIXME + key.m_texFlags |= kGLMTexDynamic; } if (Usage & D3DUSAGE_TEXTURE_SRGB) @@ -800,7 +800,7 @@ HRESULT IDirect3DDevice9::CreateVolumeTexture(UINT Width,UINT Height,UINT Depth, if (Usage & D3DUSAGE_DYNAMIC) { - GLMPRINTF(("-X- DYNAMIC tex usage ignored..")); //FIXME + key.m_texFlags |= kGLMTexDynamic; } if (Usage & D3DUSAGE_TEXTURE_SRGB)