/** * alloziert Bildspeicher für die gewünschte Größe. * * @author FloSoft */ void libsiedler2::baseArchivItem_Bitmap::tex_alloc(void) { tex_clear(); tex_width = tex_pow2(width); tex_height = tex_pow2(height); if(format == FORMAT_UNKNOWN) format = getTextureFormat(); unsigned char clear; switch(format) { case FORMAT_RGBA: tex_bpp = 4; clear = 0x00; break; case FORMAT_PALETTED: tex_bpp = 1; clear = TRANSPARENT_INDEX; break; default: tex_bpp = 0; clear = 0x7F; } tex_data.resize(tex_width * tex_height * tex_bpp, clear); }
void Canvas::setPixel( int _x, int _y, const Ogre::ColourValue & value ) { MYGUI_ASSERT( _x >= 0 && _x < getTextureRealWidth() && _y >= 0 && _y < getTextureRealHeight(), "Access to non-exists pixel! Check real dimensions of texture!" ); MYGUI_ASSERT( isLocked(), "Must lock MyGUI::Canvas before set pixel!" ); Ogre::PixelUtil::packColour( value, getTextureFormat(), pointPixel( _x, _y ) ); }
void TextureCube::setSubImage(CubeFace cf, int level, int x, int y, int w, int h, TextureFormat f, PixelType t, const Buffer::Parameters &s, const Buffer &pixels) { bindToTextureUnit(); pixels.bind(GL_PIXEL_UNPACK_BUFFER); s.set(); glTexSubImage2D(getCubeFace(cf), level, x, y, w, h, getTextureFormat(f), getPixelType(t), pixels.data(0)); s.unset(); pixels.unbind(GL_PIXEL_UNPACK_BUFFER); assert(FrameBuffer::getError() == GL_NO_ERROR); }
void Texture2DArray::setSubImage(int level, int x, int y, int l, int w, int h, int d, TextureFormat f, PixelType t, const Buffer::Parameters &s, const Buffer &pixels) { bindToTextureUnit(); pixels.bind(GL_PIXEL_UNPACK_BUFFER); s.set(); glTexSubImage3D(GL_TEXTURE_2D_ARRAY, level, x, y, l, w, h, d, getTextureFormat(f), getPixelType(t), pixels.data(0)); s.unset(); pixels.unbind(GL_PIXEL_UNPACK_BUFFER); assert(FrameBuffer::getError() == GL_NO_ERROR); }
Ogre::ColourValue Canvas::getPixel( int _x, int _y ) { MYGUI_ASSERT( _x >= 0 && _x < getTextureRealWidth() && _y >= 0 && _y < getTextureRealHeight(), "Access to non-exists pixel! Check real dimensions of texture!" ); MYGUI_ASSERT( isLocked(), "Must lock MyGUI::Canvas before set pixel!" ); Ogre::ColourValue result; Ogre::PixelUtil::unpackColour( & result, getTextureFormat(), pointPixel( _x, _y ) ); return result; }
void Texture2D::init(int w, int h, TextureInternalFormat tf, TextureFormat f, PixelType t, const Parameters ¶ms, const Buffer::Parameters &s, const Buffer &pixels) { Texture::init(tf, params); this->w = w; this->h = h; pixels.bind(GL_PIXEL_UNPACK_BUFFER); if (isCompressed() && s.compressedSize() > 0) { glCompressedTexImage2D(textureTarget, 0, getTextureInternalFormat(internalFormat), w, h, 0, s.compressedSize(), pixels.data(0)); } else { s.set(); glTexImage2D(textureTarget, 0, getTextureInternalFormat(internalFormat), w, h, 0, getTextureFormat(f), getPixelType(t), pixels.data(0)); s.unset(); } pixels.unbind(GL_PIXEL_UNPACK_BUFFER); generateMipMap(); if (FrameBuffer::getError() != 0) { throw exception(); } }
void Texture2D::setImage(int w, int h, TextureFormat f, PixelType t, const Buffer &pixels) { this->w = w; this->h = h; bindToTextureUnit(); pixels.bind(GL_PIXEL_UNPACK_BUFFER); glTexImage2D(textureTarget, 0, getTextureInternalFormat(internalFormat), w, h, 0, getTextureFormat(f), getPixelType(t), pixels.data(0)); pixels.unbind(GL_PIXEL_UNPACK_BUFFER); generateMipMap(); assert(FrameBuffer::getError() == GL_NO_ERROR); }
void TextureCube::init(int w, int h, TextureInternalFormat tf, TextureFormat f, PixelType t, const Parameters ¶ms, Buffer::Parameters s[6], ptr<Buffer> pixels[6]) { Texture::init(tf, params); this->w = w; this->h = h; const GLenum FACES[6] = { GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z }; if (isCompressed()) { for (int i = 0; i < 6; ++i) { pixels[i]->bind(GL_PIXEL_UNPACK_BUFFER); if (s[i].compressedSize() > 0) { glCompressedTexImage2D(FACES[i], 0, getTextureInternalFormat(internalFormat), w, h, 0, s[i].compressedSize(), pixels[i]->data(0)); } else { s[i].set(); glTexImage2D(FACES[i], 0, getTextureInternalFormat(internalFormat), w, h, 0, getTextureFormat(f), getPixelType(t), pixels[i]->data(0)); s[i].unset(); } pixels[i]->unbind(GL_PIXEL_UNPACK_BUFFER); } } else { for (int i = 0; i < 6; ++i) { pixels[i]->bind(GL_PIXEL_UNPACK_BUFFER); s[i].set(); glTexImage2D(FACES[i], 0, getTextureInternalFormat(internalFormat), w, h, 0, getTextureFormat(f), getPixelType(t), pixels[i]->data(0)); s[i].unset(); pixels[i]->unbind(GL_PIXEL_UNPACK_BUFFER); } } generateMipMap(); if (FrameBuffer::getError() != 0) { throw exception(); } }
void TextureRectangle::init(int w, int h, TextureInternalFormat tf, TextureFormat f, PixelType t, const Parameters ¶ms, const Buffer::Parameters &s, const Buffer &pixels) { Texture::init(tf, params); this->w = w; this->h = h; pixels.bind(GL_PIXEL_UNPACK_BUFFER); bool needToGenerateMipmaps = true; if (isCompressed() && s.compressedSize() > 0) { glCompressedTexImage2D(textureTarget, 0, getTextureInternalFormat(internalFormat), w, h, 0, s.compressedSize(), pixels.data(0)); } else { s.set(); glTexImage2D(textureTarget, 0, getTextureInternalFormat(internalFormat), w, h, 0, getTextureFormat(f), getPixelType(t), pixels.data(0)); s.unset(); GLsizei size = s.compressedSize(); // should work because size is retrieved from file descriptor. int pixelSize = getFormatSize(f, t); if (size > w * h * pixelSize) { // get the other levels from the same buffer int offset = w * h * pixelSize; int level = 0; int wl = w; int hl = h; while (wl % 2 == 0 && hl % 2 == 0 && size - offset >= (wl * hl / 4) * pixelSize) { level += 1; wl = wl / 2; hl = hl / 2; glTexImage2D(textureTarget, level, getTextureInternalFormat(internalFormat), wl, hl, 0, getTextureFormat(f), getPixelType(t), pixels.data(offset)); offset += wl * hl * pixelSize; needToGenerateMipmaps = false; } this->params.lodMax(clamp(params.lodMax(), GLfloat(0.0f), GLfloat(level))); } } pixels.unbind(GL_PIXEL_UNPACK_BUFFER); if (needToGenerateMipmaps) { generateMipMap(); } if (FrameBuffer::getError() != 0) { throw exception(); } }
CubeMapGeneratorStageDataTransitPtr CubeMapGenerator::setupStageData( RenderActionBase *pAction) { CubeMapGeneratorStageDataTransitPtr returnValue = CubeMapGeneratorStageData::createLocal(); if(returnValue == NULL) return returnValue; FrameBufferObjectUnrecPtr pCubeTarget = NULL; RenderBufferUnrecPtr pDepthBuffer = NULL; if(this->getRenderTarget() == NULL) { pCubeTarget = FrameBufferObject::createLocal(); pDepthBuffer = RenderBuffer ::createLocal(); pDepthBuffer->setInternalFormat (GL_DEPTH_COMPONENT24); pCubeTarget ->setDepthAttachment(pDepthBuffer ); returnValue ->setRenderTarget (pCubeTarget ); } else { pCubeTarget = this->getRenderTarget(); } TextureObjChunkUnrecPtr pCubeTex = NULL; if(0x0000 != (_sfSetupMode.getValue() & SetupTexture)) { pCubeTex = TextureObjChunk::createLocal(); ImageUnrecPtr pImg = Image::createLocal(); pImg->set(Image::OSG_RGB_PF, getWidth (), getHeight(), 1, 1, 1, 0.0, 0, Image::OSG_UINT8_IMAGEDATA, false, 6); pCubeTex ->setImage (pImg ); pCubeTex ->setMinFilter (GL_LINEAR ); pCubeTex ->setMagFilter (GL_LINEAR ); pCubeTex ->setWrapS (GL_CLAMP_TO_EDGE ); pCubeTex ->setWrapT (GL_CLAMP_TO_EDGE ); pCubeTex ->setWrapR (GL_CLAMP_TO_EDGE ); pCubeTex ->setInternalFormat(getTextureFormat()); } else { pCubeTex = _sfTexture.getValue(); } TextureEnvChunkUnrecPtr pCubeTexEnv = NULL; if(0x0000 != (_sfSetupMode.getValue() & SetupTexEnv)) { pCubeTexEnv = TextureEnvChunk::createLocal(); pCubeTexEnv->setEnvMode (GL_REPLACE ); } TexGenChunkUnrecPtr pCubeTexGen = NULL; TextureTransformChunkUnrecPtr pCubeTexTrans = NULL; if(0x0000 != (_sfSetupMode.getValue() & SetupTexGen)) { pCubeTexGen = TexGenChunk::createLocal(); pCubeTexGen->setGenFuncS(GL_REFLECTION_MAP); pCubeTexGen->setGenFuncT(GL_REFLECTION_MAP); pCubeTexGen->setGenFuncR(GL_REFLECTION_MAP); pCubeTexTrans = TextureTransformChunk::createLocal(); pCubeTexTrans->setUseCameraBeacon(true); } static GLenum targets[6] = { GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB, GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB }; for(UInt32 i = 0; i < 6; ++i) { TextureBufferUnrecPtr pCubeTexBuffer = TextureBuffer::createLocal(); pCubeTexBuffer->setTexture (pCubeTex ); pCubeTexBuffer->setTexTarget(targets[i]); pCubeTarget->setColorAttachment(pCubeTexBuffer, i); } pCubeTarget->setSize(getWidth (), getHeight()); if(0x0000 != (_sfSetupMode.getValue() & OverrideTex)) { returnValue->addChunk(pCubeTex, getTexUnit()); } if(0x0000 != (_sfSetupMode.getValue() & SetupTexEnv)) { returnValue->addChunk(pCubeTexEnv, getTexUnit()); } if(0x0000 != (_sfSetupMode.getValue() & SetupTexGen)) { returnValue->addChunk(pCubeTexGen, getTexUnit()); returnValue->addChunk(pCubeTexTrans, getTexUnit()); returnValue->setTexTransform(pCubeTexTrans); } if(this->getCamera() == NULL) { PerspectiveCameraUnrecPtr pCam = PerspectiveCamera::createLocal(); pCam->setNear(pAction->getCamera()->getNear()); pCam->setFar (pAction->getCamera()->getFar ()); pCam->setFov (osgDegree2Rad(90.f)); returnValue->setCamera(pCam); } return returnValue; }
bool OsmAnd::GPUAPI_OpenGL_Common::uploadSymbolAsTextureToGPU(const std::shared_ptr< const MapSymbol >& symbol, std::shared_ptr< const ResourceInGPU >& resourceInGPU) { GL_CHECK_PRESENT(glGenTextures); GL_CHECK_PRESENT(glBindTexture); GL_CHECK_PRESENT(glGenerateMipmap); GL_CHECK_PRESENT(glTexParameteri); // Determine texture properties: GLsizei sourcePixelByteSize = 0; bool symbolUsesPalette = false; switch(symbol->bitmap->getConfig()) { case SkBitmap::Config::kARGB_8888_Config: sourcePixelByteSize = 4; break; case SkBitmap::Config::kARGB_4444_Config: case SkBitmap::Config::kRGB_565_Config: sourcePixelByteSize = 2; break; case SkBitmap::Config::kIndex8_Config: sourcePixelByteSize = 1; symbolUsesPalette = true; break; default: assert(false); return false; } const auto textureFormat = getTextureFormat(symbol); // Symbols don't use mipmapping, so there is no difference between POT vs NPOT size of texture. // In OpenGLES 2.0 and OpenGL 3.0+, NPOT textures are supported in general. // OpenGLES 2.0 has some limitations without isSupported_texturesNPOT: // - no mipmaps // - only LINEAR or NEAREST minification filter. // Create texture id GLuint texture; glGenTextures(1, &texture); GL_CHECK_RESULT; assert(texture != 0); // Activate texture glBindTexture(GL_TEXTURE_2D, texture); GL_CHECK_RESULT; if(!symbolUsesPalette) { // Allocate square 2D texture allocateTexture2D(GL_TEXTURE_2D, 1, symbol->bitmap->width(), symbol->bitmap->height(), textureFormat); // Upload data uploadDataToTexture2D(GL_TEXTURE_2D, 0, 0, 0, (GLsizei)symbol->bitmap->width(), (GLsizei)symbol->bitmap->height(), symbol->bitmap->getPixels(), symbol->bitmap->rowBytes() / sourcePixelByteSize, sourcePixelByteSize, getSourceFormat(symbol)); // Set maximal mipmap level to 0 setMipMapLevelsLimit(GL_TEXTURE_2D, 0); } else { //TODO: palettes are not yet supported assert(false); } // Deselect atlas as active texture glBindTexture(GL_TEXTURE_2D, 0); GL_CHECK_RESULT; // Create resource-in-GPU descriptor const auto textureInGPU = new TextureInGPU(this, reinterpret_cast<RefInGPU>(texture), symbol->bitmap->width(), symbol->bitmap->height(), 1); resourceInGPU.reset(static_cast<ResourceInGPU*>(textureInGPU)); return true; }
bool OsmAnd::GPUAPI_OpenGL_Common::uploadTileAsTextureToGPU(const std::shared_ptr< const MapTile >& tile, std::shared_ptr< const ResourceInGPU >& resourceInGPU) { GL_CHECK_PRESENT(glGenTextures); GL_CHECK_PRESENT(glBindTexture); GL_CHECK_PRESENT(glGenerateMipmap); GL_CHECK_PRESENT(glTexParameteri); // Depending on tile type, determine texture properties: GLsizei sourcePixelByteSize = 0; bool mipmapGenerationSupported = false; bool tileUsesPalette = false; if(tile->dataType == MapTileDataType::Bitmap) { const auto bitmapTile = std::static_pointer_cast<const MapBitmapTile>(tile); switch(bitmapTile->bitmap->getConfig()) { case SkBitmap::Config::kARGB_8888_Config: sourcePixelByteSize = 4; break; case SkBitmap::Config::kARGB_4444_Config: case SkBitmap::Config::kRGB_565_Config: sourcePixelByteSize = 2; break; case SkBitmap::Config::kIndex8_Config: sourcePixelByteSize = 1; tileUsesPalette = true; break; default: assert(false); return false; } // No need to generate mipmaps if textureLod is not supported mipmapGenerationSupported = isSupported_textureLod; } else if(tile->dataType == MapTileDataType::ElevationData) { sourcePixelByteSize = 4; mipmapGenerationSupported = false; } else { assert(false); return false; } const auto textureFormat = getTextureFormat(tile); // Calculate texture size. Tiles are always stored in square textures. // Also, since atlas-texture support for tiles was deprecated, only 1 tile per texture is allowed. // If tile has NPOT size, then it needs to be rounded-up to nearest POT value const auto tileSizePOT = Utilities::getNextPowerOfTwo(tile->size); const auto textureSize = (tileSizePOT != tile->size && !isSupported_texturesNPOT) ? tileSizePOT : tile->size; const bool useAtlasTexture = (textureSize != tile->size); // Get number of mipmap levels auto mipmapLevels = 1u; if(mipmapGenerationSupported) mipmapLevels += qLn(textureSize) / M_LN2; // If tile size matches size of texture, upload is quite straightforward if(!useAtlasTexture) { // Create texture id GLuint texture; glGenTextures(1, &texture); GL_CHECK_RESULT; assert(texture != 0); // Activate texture glBindTexture(GL_TEXTURE_2D, texture); GL_CHECK_RESULT; if(!tileUsesPalette) { // Allocate square 2D texture allocateTexture2D(GL_TEXTURE_2D, mipmapLevels, textureSize, textureSize, textureFormat); // Upload data uploadDataToTexture2D(GL_TEXTURE_2D, 0, 0, 0, (GLsizei)tile->size, (GLsizei)tile->size, tile->data, tile->rowLength / sourcePixelByteSize, sourcePixelByteSize, getSourceFormat(tile)); // Set maximal mipmap level setMipMapLevelsLimit(GL_TEXTURE_2D, mipmapLevels - 1); // Generate mipmap levels if(mipmapLevels > 1) { glGenerateMipmap(GL_TEXTURE_2D); GL_CHECK_RESULT; } } else { assert(false); /* auto bitmapTile = static_cast<IMapBitmapTileProvider::Tile*>(tile.get()); // Decompress to 32bit color texture SkBitmap decompressedTexture; bitmapTile->bitmap->deepCopyTo(&decompressedTexture, SkBitmap::Config::kARGB_8888_Config); // Generate mipmaps decompressedTexture.buildMipMap(); auto generatedLevels = decompressedTexture.extractMipLevel(nullptr, SK_FixedMax, SK_FixedMax); if(mipmapLevels > generatedLevels) mipmapLevels = generatedLevels; LogPrintf(LogSeverityLevel::Info, "colors = %d", bitmapTile->bitmap->getColorTable()->count()); // For each mipmap level starting from 0, copy data to packed array // and prepare merged palette for(auto mipmapLevel = 1; mipmapLevel < mipmapLevels; mipmapLevel++) { SkBitmap mipmapLevelData; auto test22 = decompressedTexture.extractMipLevel(&mipmapLevelData, SK_Fixed1<<mipmapLevel, SK_Fixed1<<mipmapLevel); SkBitmap recomressed; recomressed.setConfig(SkBitmap::kIndex8_Config, tileSize >> mipmapLevel, tileSize >> mipmapLevel); recomressed.allocPixels(); LogPrintf(LogSeverityLevel::Info, "\tcolors = %d", recomressed.getColorTable()->count()); } //TEST: auto datasize = 256*sizeof(uint32_t) + bitmapTile->bitmap->getSize(); uint8_t* buf = new uint8_t[datasize]; for(auto colorIdx = 0; colorIdx < 256; colorIdx++) { buf[colorIdx*4 + 0] = colorIdx; buf[colorIdx*4 + 1] = colorIdx; buf[colorIdx*4 + 2] = colorIdx; buf[colorIdx*4 + 3] = 0xFF; } for(auto pixelIdx = 0; pixelIdx < tileSize*tileSize; pixelIdx++) buf[256*4 + pixelIdx] = pixelIdx % 256; glCompressedTexImage2D( GL_TEXTURE_2D, 0, GL_PALETTE8_RGBA8_OES, tileSize, tileSize, 0, datasize, buf); GL_CHECK_RESULT; delete[] buf; */ //TODO: // 1. convert to full RGBA8 // 2. generate required amount of mipmap levels // 3. glCompressedTexImage2D to load all mipmap levels at once } // Deselect atlas as active texture glBindTexture(GL_TEXTURE_2D, 0); GL_CHECK_RESULT; // Create resource-in-GPU descriptor const auto textureInGPU = new TextureInGPU(this, reinterpret_cast<RefInGPU>(texture), textureSize, textureSize, mipmapLevels); resourceInGPU.reset(static_cast<ResourceInGPU*>(textureInGPU)); return true; } // Otherwise, create an atlas texture with 1 slot only: //NOTE: No support for palette atlas textures assert(!tileUsesPalette); // Find proper atlas textures pool by format of texture and full size of tile (including padding) AtlasTypeId atlasTypeId; atlasTypeId.format = getTextureFormat(tile); atlasTypeId.tileSize = tile->size; atlasTypeId.tilePadding = 0; const auto atlasTexturesPool = obtainAtlasTexturesPool(atlasTypeId); if(!atlasTexturesPool) return false; // Get free slot from that pool const auto slotInGPU = allocateTile(atlasTexturesPool, [this, textureSize, mipmapLevels, atlasTexturesPool, tile]() -> AtlasTextureInGPU* { // Allocate texture id GLuint texture; glGenTextures(1, &texture); GL_CHECK_RESULT; assert(texture != 0); // Select this texture glBindTexture(GL_TEXTURE_2D, texture); GL_CHECK_RESULT; // Allocate space for this texture allocateTexture2D(GL_TEXTURE_2D, mipmapLevels, textureSize, textureSize, getTextureFormat(tile)); GL_CHECK_RESULT; // Set maximal mipmap level setMipMapLevelsLimit(GL_TEXTURE_2D, mipmapLevels - 1); // Deselect texture glBindTexture(GL_TEXTURE_2D, 0); GL_CHECK_RESULT; return new AtlasTextureInGPU(this, reinterpret_cast<RefInGPU>(texture), textureSize, mipmapLevels, atlasTexturesPool); }); // Upload tile to allocated slot in atlas texture // Select atlas as active texture glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(reinterpret_cast<intptr_t>(slotInGPU->atlasTexture->refInGPU))); GL_CHECK_RESULT; // Upload data uploadDataToTexture2D(GL_TEXTURE_2D, 0, 0, 0, (GLsizei)tile->size, (GLsizei)tile->size, tile->data, tile->rowLength / sourcePixelByteSize, sourcePixelByteSize, getSourceFormat(tile)); GL_CHECK_RESULT; // Generate mipmap if(slotInGPU->atlasTexture->mipmapLevels > 1) { glGenerateMipmap(GL_TEXTURE_2D); GL_CHECK_RESULT; } // Deselect atlas as active texture glBindTexture(GL_TEXTURE_2D, 0); GL_CHECK_RESULT; resourceInGPU = slotInGPU; return true; }
bool GLDriver::checkActiveTextures() { std::vector<uint8_t> untiledImage, untiledMipmap; gx2::GX2Surface surface; for (auto i = 0; i < latte::MaxTextures; ++i) { auto resourceOffset = (latte::SQ_PS_TEX_RESOURCE_0 + i) * 7; auto sq_tex_resource_word0 = getRegister<latte::SQ_TEX_RESOURCE_WORD0_N>(latte::Register::SQ_TEX_RESOURCE_WORD0_0 + 4 * resourceOffset); auto sq_tex_resource_word1 = getRegister<latte::SQ_TEX_RESOURCE_WORD1_N>(latte::Register::SQ_TEX_RESOURCE_WORD1_0 + 4 * resourceOffset); auto sq_tex_resource_word2 = getRegister<latte::SQ_TEX_RESOURCE_WORD2_N>(latte::Register::SQ_TEX_RESOURCE_WORD2_0 + 4 * resourceOffset); auto sq_tex_resource_word3 = getRegister<latte::SQ_TEX_RESOURCE_WORD3_N>(latte::Register::SQ_TEX_RESOURCE_WORD3_0 + 4 * resourceOffset); auto sq_tex_resource_word4 = getRegister<latte::SQ_TEX_RESOURCE_WORD4_N>(latte::Register::SQ_TEX_RESOURCE_WORD4_0 + 4 * resourceOffset); auto sq_tex_resource_word5 = getRegister<latte::SQ_TEX_RESOURCE_WORD5_N>(latte::Register::SQ_TEX_RESOURCE_WORD5_0 + 4 * resourceOffset); auto sq_tex_resource_word6 = getRegister<latte::SQ_TEX_RESOURCE_WORD6_N>(latte::Register::SQ_TEX_RESOURCE_WORD6_0 + 4 * resourceOffset); auto baseAddress = sq_tex_resource_word2.BASE_ADDRESS() << 8; if (!baseAddress) { continue; } if (baseAddress == mPixelTextureCache[i].baseAddress && sq_tex_resource_word0.value == mPixelTextureCache[i].word0 && sq_tex_resource_word1.value == mPixelTextureCache[i].word1 && sq_tex_resource_word2.value == mPixelTextureCache[i].word2 && sq_tex_resource_word3.value == mPixelTextureCache[i].word3 && sq_tex_resource_word4.value == mPixelTextureCache[i].word4 && sq_tex_resource_word5.value == mPixelTextureCache[i].word5 && sq_tex_resource_word6.value == mPixelTextureCache[i].word6) { continue; // No change in sampler state } mPixelTextureCache[i].baseAddress = baseAddress; mPixelTextureCache[i].word0 = sq_tex_resource_word0.value; mPixelTextureCache[i].word1 = sq_tex_resource_word1.value; mPixelTextureCache[i].word2 = sq_tex_resource_word2.value; mPixelTextureCache[i].word3 = sq_tex_resource_word3.value; mPixelTextureCache[i].word4 = sq_tex_resource_word4.value; mPixelTextureCache[i].word5 = sq_tex_resource_word5.value; mPixelTextureCache[i].word6 = sq_tex_resource_word6.value; // Decode resource registers auto pitch = (sq_tex_resource_word0.PITCH() + 1) * 8; auto width = sq_tex_resource_word0.TEX_WIDTH() + 1; auto height = sq_tex_resource_word1.TEX_HEIGHT() + 1; auto depth = sq_tex_resource_word1.TEX_DEPTH() + 1; auto format = sq_tex_resource_word1.DATA_FORMAT(); auto tileMode = sq_tex_resource_word0.TILE_MODE(); auto numFormat = sq_tex_resource_word4.NUM_FORMAT_ALL(); auto formatComp = sq_tex_resource_word4.FORMAT_COMP_X(); auto degamma = sq_tex_resource_word4.FORCE_DEGAMMA(); auto dim = sq_tex_resource_word0.DIM(); auto buffer = getSurfaceBuffer(baseAddress, width, height, depth, dim, format, numFormat, formatComp, degamma, sq_tex_resource_word0.TILE_TYPE()); if (buffer->dirtyAsTexture) { auto swizzle = sq_tex_resource_word2.SWIZZLE() << 8; // Rebuild a GX2Surface std::memset(&surface, 0, sizeof(gx2::GX2Surface)); surface.dim = static_cast<gx2::GX2SurfaceDim>(dim); surface.width = width; surface.height = height; if (surface.dim == gx2::GX2SurfaceDim::TextureCube) { surface.depth = depth * 6; } else if (surface.dim == gx2::GX2SurfaceDim::Texture3D || surface.dim == gx2::GX2SurfaceDim::Texture2DMSAAArray || surface.dim == gx2::GX2SurfaceDim::Texture2DArray || surface.dim == gx2::GX2SurfaceDim::Texture1DArray) { surface.depth = depth; } else { surface.depth = 1; } surface.mipLevels = 1; surface.format = getSurfaceFormat(format, numFormat, formatComp, degamma); surface.aa = gx2::GX2AAMode::Mode1X; surface.use = gx2::GX2SurfaceUse::Texture; if (sq_tex_resource_word0.TILE_TYPE()) { surface.use |= gx2::GX2SurfaceUse::DepthBuffer; } surface.tileMode = static_cast<gx2::GX2TileMode>(tileMode); surface.swizzle = swizzle; // Update the sizing information for the surface GX2CalcSurfaceSizeAndAlignment(&surface); // Align address baseAddress &= ~(surface.alignment - 1); surface.image = make_virtual_ptr<uint8_t>(baseAddress); surface.mipmaps = nullptr; // Calculate a new memory CRC uint64_t newHash[2] = { 0 }; MurmurHash3_x64_128(surface.image, surface.imageSize, 0, newHash); // If the CPU memory has changed, we should re-upload this. This hashing is // also means that if the application temporarily uses one of its buffers as // a color buffer, we are able to accurately handle this. Providing they are // not updating the memory at the same time. if (newHash[0] != buffer->cpuMemHash[0] || newHash[1] != buffer->cpuMemHash[1]) { buffer->cpuMemHash[0] = newHash[0]; buffer->cpuMemHash[1] = newHash[1]; // Untile gx2::internal::convertTiling(&surface, untiledImage, untiledMipmap); // Create texture auto compressed = isCompressedFormat(format); auto target = getTextureTarget(dim); auto textureDataType = gl::GL_INVALID_ENUM; auto textureFormat = getTextureFormat(format); auto size = untiledImage.size(); if (compressed) { textureDataType = getCompressedTextureDataType(format, degamma); } else { textureDataType = getTextureDataType(format, formatComp); } if (textureDataType == gl::GL_INVALID_ENUM || textureFormat == gl::GL_INVALID_ENUM) { decaf_abort(fmt::format("Texture with unsupported format {}", surface.format.value())); } switch (dim) { case latte::SQ_TEX_DIM_1D: if (compressed) { gl::glCompressedTextureSubImage1D(buffer->object, 0, /* level */ 0, /* xoffset */ width, textureDataType, gsl::narrow_cast<gl::GLsizei>(size), untiledImage.data()); } else { gl::glTextureSubImage1D(buffer->object, 0, /* level */ 0, /* xoffset */ width, textureFormat, textureDataType, untiledImage.data()); } break; case latte::SQ_TEX_DIM_2D: if (compressed) { gl::glCompressedTextureSubImage2D(buffer->object, 0, /* level */ 0, 0, /* xoffset, yoffset */ width, height, textureDataType, gsl::narrow_cast<gl::GLsizei>(size), untiledImage.data()); } else { gl::glTextureSubImage2D(buffer->object, 0, /* level */ 0, 0, /* xoffset, yoffset */ width, height, textureFormat, textureDataType, untiledImage.data()); } break; case latte::SQ_TEX_DIM_3D: if (compressed) { gl::glCompressedTextureSubImage3D(buffer->object, 0, /* level */ 0, 0, 0, /* xoffset, yoffset, zoffset */ width, height, depth, textureDataType, gsl::narrow_cast<gl::GLsizei>(size), untiledImage.data()); } else { gl::glTextureSubImage3D(buffer->object, 0, /* level */ 0, 0, 0, /* xoffset, yoffset, zoffset */ width, height, depth, textureFormat, textureDataType, untiledImage.data()); } break; case latte::SQ_TEX_DIM_CUBEMAP: decaf_check(surface.depth == 6); case latte::SQ_TEX_DIM_2D_ARRAY: if (compressed) { gl::glCompressedTextureSubImage3D(buffer->object, 0, /* level */ 0, 0, 0, /* xoffset, yoffset, zoffset */ width, height, surface.depth, textureDataType, gsl::narrow_cast<gl::GLsizei>(size), untiledImage.data()); } else { gl::glTextureSubImage3D(buffer->object, 0, /* level */ 0, 0, 0, /* xoffset, yoffset, zoffset */ width, height, surface.depth, textureFormat, textureDataType, untiledImage.data()); } break; default: decaf_abort(fmt::format("Unsupported texture dim: {}", sq_tex_resource_word0.DIM())); } } buffer->dirtyAsTexture = false; buffer->state = SurfaceUseState::CpuWritten; } // Setup texture swizzle auto dst_sel_x = getTextureSwizzle(sq_tex_resource_word4.DST_SEL_X()); auto dst_sel_y = getTextureSwizzle(sq_tex_resource_word4.DST_SEL_Y()); auto dst_sel_z = getTextureSwizzle(sq_tex_resource_word4.DST_SEL_Z()); auto dst_sel_w = getTextureSwizzle(sq_tex_resource_word4.DST_SEL_W()); gl::GLint textureSwizzle[] = { static_cast<gl::GLint>(dst_sel_x), static_cast<gl::GLint>(dst_sel_y), static_cast<gl::GLint>(dst_sel_z), static_cast<gl::GLint>(dst_sel_w), }; gl::glTextureParameteriv(buffer->object, gl::GL_TEXTURE_SWIZZLE_RGBA, textureSwizzle); gl::glBindTextureUnit(i, buffer->object); } return true; }