SurfaceBuffer * GLDriver::getDepthBuffer(latte::DB_DEPTH_BASE db_depth_base, latte::DB_DEPTH_SIZE db_depth_size, latte::DB_DEPTH_INFO db_depth_info, bool discardData) { auto baseAddress = phys_addr { (db_depth_base.BASE_256B() << 8) & 0xFFFFF800 }; auto pitch_tile_max = db_depth_size.PITCH_TILE_MAX(); auto slice_tile_max = db_depth_size.SLICE_TILE_MAX(); auto dbFormat = db_depth_info.FORMAT(); auto pitch = static_cast<uint32_t>((pitch_tile_max + 1) * latte::MicroTileWidth); auto height = static_cast<uint32_t>(((slice_tile_max + 1) * (latte::MicroTileWidth * latte::MicroTileHeight)) / pitch); auto format = latte::SQ_DATA_FORMAT::FMT_INVALID; auto numFormat = latte::SQ_NUM_FORMAT::NORM; auto formatComp = latte::SQ_FORMAT_COMP::UNSIGNED; auto degamma = 0u; switch (dbFormat) { case latte::DB_FORMAT::DEPTH_16: format = latte::SQ_DATA_FORMAT::FMT_16; numFormat = latte::SQ_NUM_FORMAT::NORM; formatComp = latte::SQ_FORMAT_COMP::UNSIGNED; degamma = 0; break; case latte::DB_FORMAT::DEPTH_8_24: format = latte::SQ_DATA_FORMAT::FMT_8_24; numFormat = latte::SQ_NUM_FORMAT::NORM; formatComp = latte::SQ_FORMAT_COMP::UNSIGNED; degamma = 0; break; case latte::DB_FORMAT::DEPTH_8_24_FLOAT: format = latte::SQ_DATA_FORMAT::FMT_8_24_FLOAT; numFormat = latte::SQ_NUM_FORMAT::SCALED; formatComp = latte::SQ_FORMAT_COMP::UNSIGNED; degamma = 0; break; case latte::DB_FORMAT::DEPTH_32_FLOAT: format = latte::SQ_DATA_FORMAT::FMT_32_FLOAT; numFormat = latte::SQ_NUM_FORMAT::SCALED; formatComp = latte::SQ_FORMAT_COMP::UNSIGNED; degamma = 0; break; case latte::DB_FORMAT::DEPTH_X24_8_32_FLOAT: format = latte::SQ_DATA_FORMAT::FMT_X24_8_32_FLOAT; numFormat = latte::SQ_NUM_FORMAT::SCALED; formatComp = latte::SQ_FORMAT_COMP::UNSIGNED; degamma = 0; break; // case latte::DEPTH_X8_24: // case latte::DEPTH_X8_24_FLOAT: // case latte::DEPTH_INVALID: default: decaf_abort(fmt::format("Depth buffer with unsupported format {}", dbFormat)); } auto tileMode = latte::getArrayModeTileMode(db_depth_info.ARRAY_MODE()); auto buffer = getSurfaceBuffer(baseAddress, pitch, pitch, height, 1, 0, latte::SQ_TEX_DIM::DIM_2D, format, numFormat, formatComp, degamma, true, tileMode, true, discardData); buffer->dirtyMemory = false; buffer->needUpload = false; buffer->state = SurfaceUseState::GpuWritten; return buffer; }
SurfaceBuffer * GLDriver::getColorBuffer(latte::CB_COLORN_BASE cb_color_base, latte::CB_COLORN_SIZE cb_color_size, latte::CB_COLORN_INFO cb_color_info, bool discardData) { auto baseAddress = phys_addr { (cb_color_base.BASE_256B() << 8) & 0xFFFFF800 }; auto pitch_tile_max = cb_color_size.PITCH_TILE_MAX(); auto slice_tile_max = cb_color_size.SLICE_TILE_MAX(); auto pitch = static_cast<uint32_t>((pitch_tile_max + 1) * latte::MicroTileWidth); auto height = static_cast<uint32_t>(((slice_tile_max + 1) * (latte::MicroTileWidth * latte::MicroTileHeight)) / pitch); auto cbNumberType = cb_color_info.NUMBER_TYPE(); auto cbFormat = cb_color_info.FORMAT(); auto format = static_cast<latte::SQ_DATA_FORMAT>(cbFormat); auto numFormat = latte::SQ_NUM_FORMAT::NORM; auto formatComp = latte::SQ_FORMAT_COMP::UNSIGNED; auto degamma = 0u; switch (cbNumberType) { case latte::CB_NUMBER_TYPE::UNORM: numFormat = latte::SQ_NUM_FORMAT::NORM; formatComp = latte::SQ_FORMAT_COMP::UNSIGNED; degamma = 0; break; case latte::CB_NUMBER_TYPE::SNORM: numFormat = latte::SQ_NUM_FORMAT::NORM; formatComp = latte::SQ_FORMAT_COMP::SIGNED; degamma = 0; break; case latte::CB_NUMBER_TYPE::UINT: numFormat = latte::SQ_NUM_FORMAT::INT; formatComp = latte::SQ_FORMAT_COMP::UNSIGNED; degamma = 0; break; case latte::CB_NUMBER_TYPE::SINT: numFormat = latte::SQ_NUM_FORMAT::INT; formatComp = latte::SQ_FORMAT_COMP::SIGNED; degamma = 0; break; case latte::CB_NUMBER_TYPE::FLOAT: numFormat = latte::SQ_NUM_FORMAT::SCALED; formatComp = latte::SQ_FORMAT_COMP::UNSIGNED; degamma = 0; break; case latte::CB_NUMBER_TYPE::SRGB: numFormat = latte::SQ_NUM_FORMAT::NORM; formatComp = latte::SQ_FORMAT_COMP::UNSIGNED; degamma = 1; break; default: decaf_abort(fmt::format("Color buffer with unsupported number type {}", cbNumberType)); } auto tileMode = latte::getArrayModeTileMode(cb_color_info.ARRAY_MODE()); auto buffer = getSurfaceBuffer(baseAddress, pitch, pitch, height, 1, 0, latte::SQ_TEX_DIM::DIM_2D, format, numFormat, formatComp, degamma, false, tileMode, true, discardData); buffer->dirtyMemory = false; buffer->needUpload = false; buffer->state = SurfaceUseState::GpuWritten; return buffer; }
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; }