Cleaning up texture info/uploading. Edge cases still likely.

This commit is contained in:
Ben Vanik 2015-02-09 14:10:07 -08:00
parent 1ffd99fe3a
commit 78451a4e9e
3 changed files with 287 additions and 324 deletions

View File

@ -412,161 +412,138 @@ void TextureSwap(Endian endianness, void* dest, const void* src,
}
}
struct TextureConfig {
TextureFormat texture_format;
GLenum internal_format;
GLenum format;
GLenum type;
};
// https://code.google.com/p/glsnewton/source/browse/trunk/Source/uDDSLoader.pas?r=62
// http://dench.flatlib.jp/opengl/textures
// http://fossies.org/linux/WebKit/Source/ThirdParty/ANGLE/src/libGLESv2/formatutils.cpp
static const TextureConfig texture_configs[64] = {
{TextureFormat::k_1_REVERSE, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_1, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM},
{TextureFormat::k_8, GL_R8, GL_RED, GL_UNSIGNED_BYTE},
{TextureFormat::k_1_5_5_5, GL_RGB5_A1, GL_BGRA,
GL_UNSIGNED_SHORT_1_5_5_5_REV},
{TextureFormat::k_5_6_5, GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5},
{TextureFormat::k_6_5_5, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM},
{TextureFormat::k_8_8_8_8, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE},
{TextureFormat::k_2_10_10_10, GL_RGB10_A2, GL_RGBA,
GL_UNSIGNED_INT_2_10_10_10_REV},
{TextureFormat::k_8_A, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM},
{TextureFormat::k_8_B, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM},
{TextureFormat::k_8_8, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM},
{TextureFormat::k_Cr_Y1_Cb_Y0, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_Y1_Cr_Y0_Cb, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::kUnknown, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_8_8_8_8_A, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_4_4_4_4, GL_RGBA4, GL_RGBA,
GL_UNSIGNED_SHORT_4_4_4_4_REV},
{TextureFormat::k_10_11_11, GL_R11F_G11F_B10F, GL_RGB,
GL_UNSIGNED_INT_10F_11F_11F_REV}, // ?
{TextureFormat::k_11_11_10, GL_R11F_G11F_B10F, GL_RGB,
GL_UNSIGNED_INT_10F_11F_11F_REV}, // ?
{TextureFormat::k_DXT1, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE},
{TextureFormat::k_DXT2_3, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_UNSIGNED_BYTE},
{TextureFormat::k_DXT4_5, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_UNSIGNED_BYTE},
{TextureFormat::kUnknown, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_24_8, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL,
GL_UNSIGNED_INT_24_8},
{TextureFormat::k_24_8_FLOAT, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL,
GL_FLOAT_32_UNSIGNED_INT_24_8_REV},
{TextureFormat::k_16, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM},
{TextureFormat::k_16_16, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM},
{TextureFormat::k_16_16_16_16, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_16_EXPAND, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_16_16_EXPAND, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_16_16_16_16_EXPAND, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_16_FLOAT, GL_R16F, GL_RED, GL_HALF_FLOAT},
{TextureFormat::k_16_16_FLOAT, GL_RG16F, GL_RG, GL_HALF_FLOAT},
{TextureFormat::k_16_16_16_16_FLOAT, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT},
{TextureFormat::k_32, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM},
{TextureFormat::k_32_32, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM},
{TextureFormat::k_32_32_32_32, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_32_FLOAT, GL_R32F, GL_RED, GL_FLOAT},
{TextureFormat::k_32_32_FLOAT, GL_RG32F, GL_RG, GL_FLOAT},
{TextureFormat::k_32_32_32_32_FLOAT, GL_RGBA32F, GL_RGBA, GL_FLOAT},
{TextureFormat::k_32_AS_8, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_32_AS_8_8, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_16_MPEG, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_16_16_MPEG, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_8_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_32_AS_8_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_32_AS_8_8_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_16_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_16_MPEG_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_16_16_MPEG_INTERLACED, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::k_DXN, GL_COMPRESSED_RG_RGTC2, GL_COMPRESSED_RG_RGTC2,
GL_INVALID_ENUM},
{TextureFormat::k_8_8_8_8_AS_16_16_16_16, GL_RGBA8, GL_RGBA,
GL_UNSIGNED_BYTE},
{TextureFormat::k_DXT1_AS_16_16_16_16, GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_UNSIGNED_BYTE},
{TextureFormat::k_DXT2_3_AS_16_16_16_16, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_UNSIGNED_BYTE},
{TextureFormat::k_DXT4_5_AS_16_16_16_16, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_UNSIGNED_BYTE},
{TextureFormat::k_2_10_10_10_AS_16_16_16_16, GL_RGB10_A2, GL_RGBA,
GL_UNSIGNED_INT_2_10_10_10_REV},
{TextureFormat::k_10_11_11_AS_16_16_16_16, GL_R11F_G11F_B10F, GL_RGB,
GL_UNSIGNED_INT_10F_11F_11F_REV},
{TextureFormat::k_11_11_10_AS_16_16_16_16, GL_R11F_G11F_B10F,
GL_INVALID_ENUM, GL_INVALID_ENUM},
{TextureFormat::k_32_32_32_FLOAT, GL_RGB32F, GL_RGB, GL_FLOAT},
{TextureFormat::k_DXT3A, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM},
{TextureFormat::k_DXT5A, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM},
{TextureFormat::k_CTX1, GL_INVALID_ENUM, GL_INVALID_ENUM, GL_INVALID_ENUM},
{TextureFormat::k_DXT3A_AS_1_1_1_1, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::kUnknown, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
{TextureFormat::kUnknown, GL_INVALID_ENUM, GL_INVALID_ENUM,
GL_INVALID_ENUM},
};
bool TextureCache::UploadTexture2D(GLuint texture,
const TextureInfo& texture_info) {
const auto host_address = memory_->Translate(texture_info.guest_address);
GLenum internal_format = GL_RGBA8;
GLenum format = GL_RGBA;
GLenum type = GL_UNSIGNED_BYTE;
// https://code.google.com/p/glsnewton/source/browse/trunk/Source/uDDSLoader.pas?r=62
// http://dench.flatlib.jp/opengl/textures
// http://fossies.org/linux/WebKit/Source/ThirdParty/ANGLE/src/libGLESv2/formatutils.cpp
switch (texture_info.format) {
case TextureFormat::k_8:
internal_format = GL_R8;
format = GL_RED;
type = GL_UNSIGNED_BYTE;
break;
case TextureFormat::k_1_5_5_5:
internal_format = GL_RGB5_A1;
format = GL_BGRA;
type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
break;
case TextureFormat::k_5_6_5:
internal_format = GL_RGB565;
format = GL_RGB;
type = GL_UNSIGNED_SHORT_5_6_5;
break;
case TextureFormat::k_2_10_10_10:
case TextureFormat::k_2_10_10_10_AS_16_16_16_16:
internal_format = GL_RGB10_A2;
format = GL_RGBA;
type = GL_UNSIGNED_INT_2_10_10_10_REV;
break;
case TextureFormat::k_10_11_11:
case TextureFormat::k_10_11_11_AS_16_16_16_16:
// ?
internal_format = GL_R11F_G11F_B10F;
format = GL_RGB;
type = GL_UNSIGNED_INT_10F_11F_11F_REV;
break;
case TextureFormat::k_11_11_10:
case TextureFormat::k_11_11_10_AS_16_16_16_16:
internal_format = GL_R11F_G11F_B10F;
format = GL_RGB;
type = GL_UNSIGNED_INT_10F_11F_11F_REV;
break;
case TextureFormat::k_8_8_8_8:
case TextureFormat::k_8_8_8_8_AS_16_16_16_16:
internal_format = GL_RGBA8;
format = GL_RGBA;
type = GL_UNSIGNED_BYTE;
break;
case TextureFormat::k_4_4_4_4:
internal_format = GL_RGBA4;
format = GL_RGBA;
type = GL_UNSIGNED_SHORT_4_4_4_4_REV;
break;
case TextureFormat::k_16_FLOAT:
internal_format = GL_R16F;
format = GL_RED;
type = GL_HALF_FLOAT;
break;
case TextureFormat::k_16_16_FLOAT:
internal_format = GL_RG16F;
format = GL_RG;
type = GL_HALF_FLOAT;
break;
case TextureFormat::k_16_16_16_16_FLOAT:
internal_format = GL_RGBA16F;
format = GL_RGBA;
type = GL_HALF_FLOAT;
break;
case TextureFormat::k_32_FLOAT:
internal_format = GL_R32F;
format = GL_RED;
type = GL_FLOAT;
break;
case TextureFormat::k_32_32_FLOAT:
internal_format = GL_RG32F;
format = GL_RG;
type = GL_FLOAT;
break;
case TextureFormat::k_32_32_32_FLOAT:
internal_format = GL_RGB32F;
format = GL_RGB;
type = GL_FLOAT;
break;
case TextureFormat::k_32_32_32_32_FLOAT:
internal_format = GL_RGBA32F;
format = GL_RGBA;
type = GL_FLOAT;
break;
case TextureFormat::k_DXT1:
case TextureFormat::k_DXT1_AS_16_16_16_16:
// or GL_COMPRESSED_RGB_S3TC_DXT1_EXT?
internal_format = format = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
break;
case TextureFormat::k_DXT2_3:
case TextureFormat::k_DXT2_3_AS_16_16_16_16:
internal_format = format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
break;
case TextureFormat::k_DXT4_5:
case TextureFormat::k_DXT4_5_AS_16_16_16_16:
internal_format = format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
break;
case TextureFormat::k_DXN:
internal_format = format = GL_COMPRESSED_RG_RGTC2;
break;
case TextureFormat::k_24_8:
internal_format = GL_DEPTH24_STENCIL8;
format = GL_DEPTH_STENCIL;
type = GL_UNSIGNED_INT_24_8;
break;
case TextureFormat::k_24_8_FLOAT:
internal_format = GL_DEPTH24_STENCIL8;
format = GL_DEPTH_STENCIL;
type = GL_FLOAT_32_UNSIGNED_INT_24_8_REV;
break;
default:
case TextureFormat::k_1_REVERSE:
case TextureFormat::k_1:
case TextureFormat::k_6_5_5:
case TextureFormat::k_8_A:
case TextureFormat::k_8_B:
case TextureFormat::k_8_8:
case TextureFormat::k_Cr_Y1_Cb_Y0:
case TextureFormat::k_Y1_Cr_Y0_Cb:
case TextureFormat::k_8_8_8_8_A:
case TextureFormat::k_16:
case TextureFormat::k_16_16:
case TextureFormat::k_16_16_16_16:
case TextureFormat::k_16_EXPAND:
case TextureFormat::k_16_16_EXPAND:
case TextureFormat::k_16_16_16_16_EXPAND:
case TextureFormat::k_32_32:
case TextureFormat::k_32_32_32_32:
case TextureFormat::k_32_AS_8:
case TextureFormat::k_32_AS_8_8:
case TextureFormat::k_16_MPEG:
case TextureFormat::k_16_16_MPEG:
case TextureFormat::k_8_INTERLACED:
case TextureFormat::k_32_AS_8_INTERLACED:
case TextureFormat::k_32_AS_8_8_INTERLACED:
case TextureFormat::k_16_INTERLACED:
case TextureFormat::k_16_MPEG_INTERLACED:
case TextureFormat::k_16_16_MPEG_INTERLACED:
case TextureFormat::k_DXT3A:
case TextureFormat::k_DXT5A:
case TextureFormat::k_CTX1:
case TextureFormat::k_DXT3A_AS_1_1_1_1:
assert_unhandled_case(texture_info.format);
const auto& config =
texture_configs[uint32_t(texture_info.format_info->format)];
if (config.format == GL_INVALID_ENUM) {
assert_always("Unhandled texture format");
return false;
}
size_t unpack_length = texture_info.input_length;
glTextureStorage2D(texture, 1, internal_format,
size_t unpack_length = texture_info.output_length;
glTextureStorage2D(texture, 1, config.internal_format,
texture_info.size_2d.output_width,
texture_info.size_2d.output_height);
assert_true(unpack_length % 4 == 0);
@ -574,8 +551,7 @@ bool TextureCache::UploadTexture2D(GLuint texture,
auto allocation = scratch_buffer_->Acquire(unpack_length);
if (!texture_info.is_tiled) {
if (texture_info.size_2d.input_pitch ==
texture_info.size_2d.logical_pitch) {
if (texture_info.size_2d.input_pitch == texture_info.size_2d.output_pitch) {
// Fast path copy entire image.
TextureSwap(texture_info.endianness, allocation.host_ptr, host_address,
unpack_length);
@ -585,11 +561,12 @@ bool TextureCache::UploadTexture2D(GLuint texture,
// this exact thing under the covers, so we just always do it here.
const uint8_t* src = host_address;
uint8_t* dest = reinterpret_cast<uint8_t*>(allocation.host_ptr);
uint32_t pitch = std::min(texture_info.size_2d.input_pitch,
texture_info.size_2d.output_pitch);
for (uint32_t y = 0; y < texture_info.size_2d.block_height; y++) {
TextureSwap(texture_info.endianness, dest, src,
texture_info.size_2d.logical_pitch);
TextureSwap(texture_info.endianness, dest, src, pitch);
src += texture_info.size_2d.input_pitch;
dest += texture_info.size_2d.logical_pitch;
dest += texture_info.size_2d.output_pitch;
}
}
} else {
@ -598,26 +575,26 @@ bool TextureCache::UploadTexture2D(GLuint texture,
// TODO(benvanik): optimize this inner loop (or work by tiles).
const uint8_t* src = host_address;
uint8_t* dest = reinterpret_cast<uint8_t*>(allocation.host_ptr);
uint32_t output_pitch =
(texture_info.size_2d.output_width / texture_info.block_size) *
texture_info.texel_pitch;
auto bpp =
(texture_info.texel_pitch >> 2) +
((texture_info.texel_pitch >> 1) >> (texture_info.texel_pitch >> 2));
uint32_t bytes_per_block = texture_info.format_info->block_width *
texture_info.format_info->block_height *
texture_info.format_info->bits_per_pixel / 8;
auto bpp = (bytes_per_block >> 2) +
((bytes_per_block >> 1) >> (bytes_per_block >> 2));
for (uint32_t y = 0, output_base_offset = 0;
y < texture_info.size_2d.block_height;
y++, output_base_offset += output_pitch) {
y++, output_base_offset += texture_info.size_2d.output_pitch) {
auto input_base_offset = TextureInfo::TiledOffset2DOuter(
y, (texture_info.size_2d.input_width / texture_info.block_size), bpp);
y, (texture_info.size_2d.input_width /
texture_info.format_info->block_width),
bpp);
for (uint32_t x = 0, output_offset = output_base_offset;
x < texture_info.size_2d.block_width;
x++, output_offset += texture_info.texel_pitch) {
x++, output_offset += bytes_per_block) {
auto input_offset =
TextureInfo::TiledOffset2DInner(x, y, bpp, input_base_offset) >>
bpp;
TextureSwap(texture_info.endianness, dest + output_offset,
src + input_offset * texture_info.texel_pitch,
texture_info.texel_pitch);
src + input_offset * bytes_per_block, bytes_per_block);
}
}
}
@ -628,10 +605,10 @@ bool TextureCache::UploadTexture2D(GLuint texture,
scratch_buffer_->Flush();
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, scratch_buffer_->handle());
if (texture_info.is_compressed) {
glCompressedTextureSubImage2D(texture, 0, 0, 0,
texture_info.size_2d.output_width,
texture_info.size_2d.output_height, format,
if (texture_info.is_compressed()) {
glCompressedTextureSubImage2D(
texture, 0, 0, 0, texture_info.size_2d.output_width,
texture_info.size_2d.output_height, config.format,
static_cast<GLsizei>(unpack_length),
reinterpret_cast<void*>(unpack_offset));
} else {
@ -642,8 +619,8 @@ bool TextureCache::UploadTexture2D(GLuint texture,
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTextureSubImage2D(texture, 0, 0, 0, texture_info.size_2d.output_width,
texture_info.size_2d.output_height, format, type,
reinterpret_cast<void*>(unpack_offset));
texture_info.size_2d.output_height, config.format,
config.type, reinterpret_cast<void*>(unpack_offset));
}
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
return true;

View File

@ -19,6 +19,78 @@ namespace gpu {
using namespace xe::gpu::ucode;
using namespace xe::gpu::xenos;
static const FormatInfo format_infos[64] = {
{TextureFormat::k_1_REVERSE, FormatType::kUncompressed, 1, 1, 1},
{TextureFormat::k_1, FormatType::kUncompressed, 1, 1, 1},
{TextureFormat::k_8, FormatType::kUncompressed, 1, 1, 8},
{TextureFormat::k_1_5_5_5, FormatType::kUncompressed, 1, 1, 16},
{TextureFormat::k_5_6_5, FormatType::kUncompressed, 1, 1, 16},
{TextureFormat::k_6_5_5, FormatType::kUncompressed, 1, 1, 16},
{TextureFormat::k_8_8_8_8, FormatType::kUncompressed, 1, 1, 32},
{TextureFormat::k_2_10_10_10, FormatType::kUncompressed, 1, 1, 32},
{TextureFormat::k_8_A, FormatType::kUncompressed, 1, 1, 8},
{TextureFormat::k_8_B, FormatType::kUncompressed, 1, 1, 8},
{TextureFormat::k_8_8, FormatType::kUncompressed, 1, 1, 16},
{TextureFormat::k_Cr_Y1_Cb_Y0, FormatType::kCompressed, 2, 1, 16},
{TextureFormat::k_Y1_Cr_Y0_Cb, FormatType::kCompressed, 2, 1, 16},
{TextureFormat::kUnknown, FormatType::kUncompressed, 0, 0},
{TextureFormat::k_8_8_8_8_A, FormatType::kUncompressed, 1, 1, 32},
{TextureFormat::k_4_4_4_4, FormatType::kUncompressed, 1, 1, 16},
{TextureFormat::k_10_11_11, FormatType::kUncompressed, 1, 1, 32},
{TextureFormat::k_11_11_10, FormatType::kUncompressed, 1, 1, 32},
{TextureFormat::k_DXT1, FormatType::kCompressed, 4, 4, 4},
{TextureFormat::k_DXT2_3, FormatType::kCompressed, 4, 4, 8},
{TextureFormat::k_DXT4_5, FormatType::kCompressed, 4, 4, 8},
{TextureFormat::kUnknown, FormatType::kUncompressed, 0, 0},
{TextureFormat::k_24_8, FormatType::kUncompressed, 1, 1, 32},
{TextureFormat::k_24_8_FLOAT, FormatType::kUncompressed, 1, 1, 32},
{TextureFormat::k_16, FormatType::kUncompressed, 1, 1, 16},
{TextureFormat::k_16_16, FormatType::kUncompressed, 1, 1, 32},
{TextureFormat::k_16_16_16_16, FormatType::kUncompressed, 1, 1, 64},
{TextureFormat::k_16_EXPAND, FormatType::kUncompressed, 1, 1, 16},
{TextureFormat::k_16_16_EXPAND, FormatType::kUncompressed, 1, 1, 32},
{TextureFormat::k_16_16_16_16_EXPAND, FormatType::kUncompressed, 1, 1, 64},
{TextureFormat::k_16_FLOAT, FormatType::kUncompressed, 1, 1, 16},
{TextureFormat::k_16_16_FLOAT, FormatType::kUncompressed, 1, 1, 32},
{TextureFormat::k_16_16_16_16_FLOAT, FormatType::kUncompressed, 1, 1, 64},
{TextureFormat::k_32, FormatType::kUncompressed, 1, 1, 32},
{TextureFormat::k_32_32, FormatType::kUncompressed, 1, 1, 64},
{TextureFormat::k_32_32_32_32, FormatType::kUncompressed, 1, 1, 128},
{TextureFormat::k_32_FLOAT, FormatType::kUncompressed, 1, 1, 32},
{TextureFormat::k_32_32_FLOAT, FormatType::kUncompressed, 1, 1, 64},
{TextureFormat::k_32_32_32_32_FLOAT, FormatType::kUncompressed, 1, 1, 128},
{TextureFormat::k_32_AS_8, FormatType::kCompressed, 4, 1, 8},
{TextureFormat::k_32_AS_8_8, FormatType::kCompressed, 2, 1, 16},
{TextureFormat::k_16_MPEG, FormatType::kUncompressed, 1, 1, 16},
{TextureFormat::k_16_16_MPEG, FormatType::kUncompressed, 1, 1, 32},
{TextureFormat::k_8_INTERLACED, FormatType::kUncompressed, 1, 1, 8},
{TextureFormat::k_32_AS_8_INTERLACED, FormatType::kCompressed, 4, 1, 8},
{TextureFormat::k_32_AS_8_8_INTERLACED, FormatType::kCompressed, 1, 1, 16},
{TextureFormat::k_16_INTERLACED, FormatType::kUncompressed, 1, 1, 16},
{TextureFormat::k_16_MPEG_INTERLACED, FormatType::kUncompressed, 1, 1, 16},
{TextureFormat::k_16_16_MPEG_INTERLACED, FormatType::kUncompressed, 1, 1,
32},
{TextureFormat::k_DXN, FormatType::kCompressed, 4, 4, 8},
{TextureFormat::k_8_8_8_8_AS_16_16_16_16, FormatType::kUncompressed, 1, 1,
32},
{TextureFormat::k_DXT1_AS_16_16_16_16, FormatType::kCompressed, 4, 4, 4},
{TextureFormat::k_DXT2_3_AS_16_16_16_16, FormatType::kCompressed, 4, 4, 8},
{TextureFormat::k_DXT4_5_AS_16_16_16_16, FormatType::kCompressed, 4, 4, 8},
{TextureFormat::k_2_10_10_10_AS_16_16_16_16, FormatType::kUncompressed, 1,
1, 32},
{TextureFormat::k_10_11_11_AS_16_16_16_16, FormatType::kUncompressed, 1, 1,
32},
{TextureFormat::k_11_11_10_AS_16_16_16_16, FormatType::kUncompressed, 1, 1,
32},
{TextureFormat::k_32_32_32_FLOAT, FormatType::kUncompressed, 1, 1, 96},
{TextureFormat::k_DXT3A, FormatType::kCompressed, 4, 4, 4},
{TextureFormat::k_DXT5A, FormatType::kCompressed, 4, 4, 4},
{TextureFormat::k_CTX1, FormatType::kCompressed, 4, 4, 4},
{TextureFormat::k_DXT3A_AS_1_1_1_1, FormatType::kCompressed, 4, 4, 4},
{TextureFormat::kUnknown, FormatType::kUncompressed, 0, 0},
{TextureFormat::kUnknown, FormatType::kUncompressed, 0, 0},
};
bool TextureInfo::Prepare(const xe_gpu_texture_fetch_t& fetch,
TextureInfo* out_info) {
std::memset(out_info, 0, sizeof(TextureInfo));
@ -46,125 +118,20 @@ bool TextureInfo::Prepare(const xe_gpu_texture_fetch_t& fetch,
info.depth = fetch.size_3d.depth;
break;
}
info.format_info = &format_infos[fetch.format];
info.endianness = static_cast<Endian>(fetch.endianness);
info.block_size = 0;
info.texel_pitch = 0;
info.is_tiled = fetch.tiled;
info.is_compressed = false;
info.input_length = 0;
info.format = static_cast<TextureFormat>(fetch.format);
switch (fetch.format) {
case FMT_8:
info.block_size = 1;
info.texel_pitch = 1;
break;
case FMT_1_5_5_5:
info.block_size = 1;
info.texel_pitch = 2;
break;
case FMT_8_8_8_8:
case FMT_8_8_8_8_AS_16_16_16_16:
info.block_size = 1;
info.texel_pitch = 4;
break;
case FMT_4_4_4_4:
info.block_size = 1;
info.texel_pitch = 2;
break;
case FMT_16_16_16_16_FLOAT:
info.block_size = 1;
info.texel_pitch = 8;
break;
case FMT_32_FLOAT:
info.block_size = 1;
info.texel_pitch = 4;
break;
case FMT_DXT1:
info.block_size = 4;
info.texel_pitch = 8;
info.is_compressed = true;
break;
case FMT_DXT2_3:
case FMT_DXT4_5:
info.block_size = 4;
info.texel_pitch = 16;
info.is_compressed = true;
break;
case FMT_DXN:
// BC5
info.block_size = 4;
info.texel_pitch = 16;
info.is_compressed = true;
break;
case FMT_DXT1_AS_16_16_16_16:
// TODO(benvanik): conversion?
info.block_size = 4;
info.texel_pitch = 8;
info.is_compressed = true;
break;
case FMT_DXT2_3_AS_16_16_16_16:
case FMT_DXT4_5_AS_16_16_16_16:
// TODO(benvanik): conversion?
info.block_size = 4;
info.texel_pitch = 16;
info.is_compressed = true;
break;
case FMT_1_REVERSE:
case FMT_1:
case FMT_5_6_5:
case FMT_6_5_5:
case FMT_2_10_10_10:
case FMT_8_A:
case FMT_8_B:
case FMT_8_8:
case FMT_Cr_Y1_Cb_Y0:
case FMT_Y1_Cr_Y0_Cb:
case FMT_5_5_5_1:
case FMT_8_8_8_8_A:
case FMT_10_11_11:
case FMT_11_11_10:
case FMT_24_8:
case FMT_24_8_FLOAT:
case FMT_16:
case FMT_16_16:
case FMT_16_16_16_16:
case FMT_16_EXPAND:
case FMT_16_16_EXPAND:
case FMT_16_16_16_16_EXPAND:
case FMT_16_FLOAT:
case FMT_16_16_FLOAT:
case FMT_32:
case FMT_32_32:
case FMT_32_32_32_32:
case FMT_32_32_FLOAT:
case FMT_32_32_32_32_FLOAT:
case FMT_32_AS_8:
case FMT_32_AS_8_8:
case FMT_16_MPEG:
case FMT_16_16_MPEG:
case FMT_8_INTERLACED:
case FMT_32_AS_8_INTERLACED:
case FMT_32_AS_8_8_INTERLACED:
case FMT_16_INTERLACED:
case FMT_16_MPEG_INTERLACED:
case FMT_16_16_MPEG_INTERLACED:
case FMT_2_10_10_10_AS_16_16_16_16:
case FMT_10_11_11_AS_16_16_16_16:
case FMT_11_11_10_AS_16_16_16_16:
case FMT_32_32_32_FLOAT:
case FMT_DXT3A:
case FMT_DXT5A:
case FMT_CTX1:
case FMT_DXT3A_AS_1_1_1_1:
PLOGE("Unhandled texture format");
return false;
default:
assert_unhandled_case(fetch.format);
info.input_length = 0; // Populated below.
info.output_length = 0;
if (info.format_info->format == TextureFormat::kUnknown) {
assert_true("Unsupported texture format");
return false;
}
// Must be called here when we know the format.
info.input_length = 0; // Populated below.
info.output_length = 0;
switch (info.dimension) {
case Dimension::k1D:
info.CalculateTextureSizes1D(fetch);
@ -192,39 +159,44 @@ void TextureInfo::CalculateTextureSizes2D(const xe_gpu_texture_fetch_t& fetch) {
size_2d.logical_width = 1 + fetch.size_2d.width;
size_2d.logical_height = 1 + fetch.size_2d.height;
size_2d.block_width = size_2d.logical_width / block_size;
size_2d.block_height = size_2d.logical_height / block_size;
if (!is_compressed) {
// Must be 32x32 but also must have a pitch that is a multiple of 256 bytes.
uint32_t bytes_per_block = block_size * block_size * texel_pitch;
uint32_t width_multiple = 32;
// Here be dragons. The values here are used in texture_cache.cc to copy
// images and create GL textures. Changes here will impact that code.
// TODO(benvanik): generic texture copying utility.
// w/h in blocks must be a multiple of block size.
uint32_t block_width =
poly::round_up(size_2d.logical_width, format_info->block_width) /
format_info->block_width;
uint32_t block_height =
poly::round_up(size_2d.logical_height, format_info->block_height) /
format_info->block_height;
// Tiles are 32x32 blocks. All textures must be multiples of tile dimensions.
uint32_t tile_width = uint32_t(std::ceilf(block_width / 32.0f));
uint32_t tile_height = uint32_t(std::ceilf(block_height / 32.0f));
size_2d.block_width = tile_width * 32;
size_2d.block_height = tile_height * 32;
uint32_t bytes_per_block = format_info->block_width *
format_info->block_height *
format_info->bits_per_pixel / 8;
uint32_t byte_pitch = tile_width * 32 * bytes_per_block;
if (!is_tiled) {
// 256 stride requirement for untiled textures.
width_multiple = poly::round_up(width_multiple, 256 / bytes_per_block);
// Each row must be a multiple of 256 in linear textures.
byte_pitch = poly::round_up(byte_pitch, 256);
}
size_2d.input_width = poly::round_up(size_2d.logical_width, width_multiple);
size_2d.input_height = poly::round_up(size_2d.logical_height, 32);
size_2d.output_width = size_2d.logical_width;
size_2d.output_height = size_2d.logical_height;
size_2d.logical_pitch = (size_2d.logical_width / block_size) * texel_pitch;
size_2d.input_pitch = (size_2d.input_width / block_size) * texel_pitch;
input_length = size_2d.block_height * size_2d.logical_pitch; // ?
} else {
// Must be 128x128 minimum (block_size * 32).
size_2d.input_width =
poly::round_up(size_2d.logical_width, block_size * 32);
size_2d.input_height =
poly::round_up(size_2d.logical_height, block_size * 32);
size_2d.output_width = size_2d.input_width;
size_2d.output_height = size_2d.input_height;
size_2d.input_width = tile_width * 32 * format_info->block_width;
size_2d.input_height = tile_height * 32 * format_info->block_height;
uint32_t block_count = (size_2d.input_width / block_size) *
(size_2d.input_height / block_size);
size_2d.logical_pitch = (size_2d.input_width / block_size) * texel_pitch;
size_2d.input_pitch = (size_2d.input_width / block_size) * texel_pitch;
input_length = block_count * texel_pitch;
}
size_2d.output_width = block_width * format_info->block_width;
size_2d.output_height = block_height * format_info->block_height;
size_2d.input_pitch = byte_pitch;
size_2d.output_pitch = block_width * bytes_per_block;
input_length = size_2d.input_pitch * size_2d.block_height;
output_length = size_2d.output_pitch * block_height;
}
// https://code.google.com/p/crunch/source/browse/trunk/inc/crn_decomp.h#4104

View File

@ -84,21 +84,35 @@ enum class TextureFormat : uint32_t {
kUnknown = 0xFFFFFFFFu,
};
enum class FormatType {
kUncompressed,
kCompressed,
};
struct FormatInfo {
TextureFormat format;
FormatType type;
uint32_t block_width;
uint32_t block_height;
uint32_t bits_per_pixel;
};
struct TextureInfo {
uint32_t guest_address;
uint32_t input_length;
uint32_t swizzle;
Dimension dimension;
uint32_t width;
uint32_t height;
uint32_t depth;
uint32_t block_size;
uint32_t texel_pitch;
const FormatInfo* format_info;
xenos::Endian endianness;
bool is_tiled;
bool is_compressed;
uint32_t input_length;
uint32_t output_length;
TextureFormat format;
bool is_compressed() const {
return format_info->type == FormatType::kCompressed;
}
union {
struct {
@ -111,10 +125,10 @@ struct TextureInfo {
uint32_t block_height;
uint32_t input_width;
uint32_t input_height;
uint32_t input_pitch;
uint32_t output_width;
uint32_t output_height;
uint32_t logical_pitch;
uint32_t input_pitch;
uint32_t output_pitch;
} size_2d;
struct {
} size_3d;