uint32 UTextureCube::CalcTextureMemorySizeEnum( ETextureMipCount Enum ) const { if ( Enum == TMC_ResidentMips || Enum == TMC_AllMipsBiased ) { return CalcTextureMemorySize( GetNumMips() - LODBias ); } else { return CalcTextureMemorySize( GetNumMips() ); } }
FTextureResource* UTextureCube::CreateResource() { FTextureResource* NewResource = NULL; if (GetNumMips() > 0) { NewResource = new FTextureCubeResource(this); } return NewResource; }
uint32 UTextureCube::CalcTextureMemorySize( int32 MipCount ) const { uint32 Size = 0; if (PlatformData) { int32 SizeX = GetSizeX(); int32 SizeY = GetSizeY(); int32 NumMips = GetNumMips(); EPixelFormat Format = GetPixelFormat(); ensureMsgf(SizeX == SizeY, TEXT("Cubemap faces expected to be square. Actual sizes are: %i, %i"), SizeX, SizeY); // Figure out what the first mip to use is. int32 FirstMip = FMath::Max( 0, NumMips - MipCount ); FIntPoint MipExtents = CalcMipMapExtent(SizeX, SizeY, Format, FirstMip); uint32 TextureAlign = 0; uint64 TextureSize = RHICalcTextureCubePlatformSize(MipExtents.X, Format, NumMips, 0, TextureAlign); Size = (uint32)TextureSize; } return Size; }
bool WrappedOpenGL::Serialise_wglDXLockObjectsNV(SerialiserType &ser, GLResource Resource) { SERIALISE_ELEMENT(Resource); SERIALISE_ELEMENT_LOCAL(textype, Resource.Namespace == eResBuffer ? eGL_NONE : m_Textures[GetResourceManager()->GetID(Resource)].curType) .Hidden(); const GLHookSet &gl = m_Real; // buffer contents are easier to save if(textype == eGL_NONE) { byte *Contents = NULL; uint32_t length = 1; // while writing, fetch the buffer's size and contents if(ser.IsWriting()) { gl.glGetNamedBufferParameterivEXT(Resource.name, eGL_BUFFER_SIZE, (GLint *)&length); Contents = new byte[length]; GLuint oldbuf = 0; gl.glGetIntegerv(eGL_COPY_READ_BUFFER_BINDING, (GLint *)&oldbuf); gl.glBindBuffer(eGL_COPY_READ_BUFFER, Resource.name); gl.glGetBufferSubData(eGL_COPY_READ_BUFFER, 0, (GLsizeiptr)length, Contents); gl.glBindBuffer(eGL_COPY_READ_BUFFER, oldbuf); } SERIALISE_ELEMENT_ARRAY(Contents, length); SERIALISE_CHECK_READ_ERRORS(); // restore on replay if(IsReplayingAndReading()) { uint32_t liveLength = 1; gl.glGetNamedBufferParameterivEXT(Resource.name, eGL_BUFFER_SIZE, (GLint *)&liveLength); gl.glNamedBufferSubData(Resource.name, 0, (GLsizeiptr)RDCMIN(length, liveLength), Contents); } } else { GLuint ppb = 0, pub = 0; PixelPackState pack; PixelUnpackState unpack; // save and restore pixel pack/unpack state. We only need one or the other but for clarity we // push and pop both always. if(ser.IsWriting() || !IsStructuredExporting(m_State)) { gl.glGetIntegerv(eGL_PIXEL_PACK_BUFFER_BINDING, (GLint *)&ppb); gl.glGetIntegerv(eGL_PIXEL_UNPACK_BUFFER_BINDING, (GLint *)&pub); gl.glBindBuffer(eGL_PIXEL_PACK_BUFFER, 0); gl.glBindBuffer(eGL_PIXEL_UNPACK_BUFFER, 0); pack.Fetch(&gl, false); unpack.Fetch(&gl, false); ResetPixelPackState(gl, false, 1); ResetPixelUnpackState(gl, false, 1); } TextureData &details = m_Textures[GetResourceManager()->GetID(Resource)]; GLuint tex = Resource.name; // serialise the metadata for convenience SERIALISE_ELEMENT_LOCAL(internalFormat, details.internalFormat).Hidden(); SERIALISE_ELEMENT_LOCAL(width, details.width).Hidden(); SERIALISE_ELEMENT_LOCAL(height, details.height).Hidden(); SERIALISE_ELEMENT_LOCAL(depth, details.depth).Hidden(); RDCASSERT(internalFormat == details.internalFormat, internalFormat, details.internalFormat); RDCASSERT(width == details.width, width, details.width); RDCASSERT(height == details.height, height, details.height); RDCASSERT(depth == details.depth, depth, details.depth); GLenum fmt = GetBaseFormat(internalFormat); GLenum type = GetDataType(internalFormat); GLint dim = details.dimension; uint32_t size = (uint32_t)GetByteSize(width, height, depth, fmt, type); int mips = 0; if(IsReplayingAndReading()) mips = GetNumMips(gl, textype, tex, width, height, depth); byte *scratchBuf = NULL; // on read and write, we allocate a single buffer big enough for all mips and re-use it // to avoid repeated new/free. scratchBuf = AllocAlignedBuffer(size); GLuint prevtex = 0; if(!IsStructuredExporting(m_State)) { gl.glGetIntegerv(TextureBinding(details.curType), (GLint *)&prevtex); gl.glBindTexture(textype, tex); } for(int i = 0; i < mips; i++) { int w = RDCMAX(details.width >> i, 1); int h = RDCMAX(details.height >> i, 1); int d = RDCMAX(details.depth >> i, 1); if(textype == eGL_TEXTURE_CUBE_MAP_ARRAY || textype == eGL_TEXTURE_1D_ARRAY || textype == eGL_TEXTURE_2D_ARRAY) d = details.depth; size = (uint32_t)GetByteSize(w, h, d, fmt, type); GLenum targets[] = { eGL_TEXTURE_CUBE_MAP_POSITIVE_X, eGL_TEXTURE_CUBE_MAP_NEGATIVE_X, eGL_TEXTURE_CUBE_MAP_POSITIVE_Y, eGL_TEXTURE_CUBE_MAP_NEGATIVE_Y, eGL_TEXTURE_CUBE_MAP_POSITIVE_Z, eGL_TEXTURE_CUBE_MAP_NEGATIVE_Z, }; int count = ARRAY_COUNT(targets); if(textype != eGL_TEXTURE_CUBE_MAP) { targets[0] = textype; count = 1; } for(int trg = 0; trg < count; trg++) { if(ser.IsWriting()) { // we avoid glGetTextureImageEXT as it seems buggy for cubemap faces gl.glGetTexImage(targets[trg], i, fmt, type, scratchBuf); } // serialise without allocating memory as we already have our scratch buf sized. ser.Serialise("SubresourceContents", scratchBuf, size, SerialiserFlags::NoFlags); if(IsReplayingAndReading() && !ser.IsErrored()) { if(dim == 1) gl.glTextureSubImage1DEXT(tex, targets[trg], i, 0, w, fmt, type, scratchBuf); else if(dim == 2) gl.glTextureSubImage2DEXT(tex, targets[trg], i, 0, 0, w, h, fmt, type, scratchBuf); else if(dim == 3) gl.glTextureSubImage3DEXT(tex, targets[trg], i, 0, 0, 0, w, h, d, fmt, type, scratchBuf); } } } FreeAlignedBuffer(scratchBuf); // restore pixel (un)packing state if(ser.IsWriting() || !IsStructuredExporting(m_State)) { gl.glBindBuffer(eGL_PIXEL_PACK_BUFFER, ppb); gl.glBindBuffer(eGL_PIXEL_UNPACK_BUFFER, pub); pack.Apply(&gl, false); unpack.Apply(&gl, false); } if(!IsStructuredExporting(m_State)) gl.glBindTexture(textype, prevtex); SERIALISE_CHECK_READ_ERRORS(); } return true; }