diff --git a/hw/xbox/nv2a/pgraph/vk/constants.h b/hw/xbox/nv2a/pgraph/vk/constants.h index 60e72046a5..2cdce981ef 100644 --- a/hw/xbox/nv2a/pgraph/vk/constants.h +++ b/hw/xbox/nv2a/pgraph/vk/constants.h @@ -164,11 +164,20 @@ static const VkColorFormatInfo kelvin_color_format_vk_map[66] = { { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R } }, [NV097_SET_TEXTURE_FORMAT_COLOR_SZ_A1R5G5B5] = { +#ifdef __ANDROID__ + VK_FORMAT_R8G8B8A8_UNORM, // Converted +#else VK_FORMAT_A1R5G5B5_UNORM_PACK16, +#endif }, [NV097_SET_TEXTURE_FORMAT_COLOR_SZ_X1R5G5B5] = { +#ifdef __ANDROID__ + VK_FORMAT_R8G8B8A8_UNORM, // Converted + { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_ONE }, +#else VK_FORMAT_A1R5G5B5_UNORM_PACK16, { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_ONE }, +#endif }, [NV097_SET_TEXTURE_FORMAT_COLOR_SZ_A4R4G4B4] = { VK_FORMAT_R8G8B8A8_UNORM, // Converted @@ -196,7 +205,11 @@ static const VkColorFormatInfo kelvin_color_format_vk_map[66] = { VK_FORMAT_R8G8B8A8_UNORM, // Converted }, [NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_A1R5G5B5] = { +#ifdef __ANDROID__ + VK_FORMAT_R8G8B8A8_UNORM, // Converted +#else VK_FORMAT_A1R5G5B5_UNORM_PACK16, +#endif }, [NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_R5G6B5] = { VK_FORMAT_R5G6B5_UNORM_PACK16, @@ -225,8 +238,13 @@ static const VkColorFormatInfo kelvin_color_format_vk_map[66] = { { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R } }, [NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_X1R5G5B5] = { +#ifdef __ANDROID__ + VK_FORMAT_R8G8B8A8_UNORM, // Converted + { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_ONE }, +#else VK_FORMAT_A1R5G5B5_UNORM_PACK16, { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_ONE }, +#endif }, [NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_A4R4G4B4] = { VK_FORMAT_R8G8B8A8_UNORM, // Converted diff --git a/hw/xbox/nv2a/pgraph/vk/texture.c b/hw/xbox/nv2a/pgraph/vk/texture.c index cea205f167..3ed3487bf7 100644 --- a/hw/xbox/nv2a/pgraph/vk/texture.c +++ b/hw/xbox/nv2a/pgraph/vk/texture.c @@ -51,6 +51,68 @@ static VkSamplerAddressMode lookup_texture_address_mode(int idx) return pgraph_texture_addr_vk_map[idx]; } +#ifdef __ANDROID__ +static uint8_t android_vk_expand_5_to_8(uint8_t value) +{ + return (value << 3) | (value >> 2); +} + +static bool android_vk_texture_needs_rgba8_upload(TextureShape s) +{ + switch (s.color_format) { + case NV097_SET_TEXTURE_FORMAT_COLOR_SZ_A1R5G5B5: + case NV097_SET_TEXTURE_FORMAT_COLOR_SZ_X1R5G5B5: + case NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_A1R5G5B5: + case NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_X1R5G5B5: + return true; + default: + return false; + } +} + +static uint8_t *android_vk_texture_convert_to_rgba8(TextureShape s, + const uint8_t *src, + unsigned int width, + unsigned int height, + unsigned int depth, + unsigned int row_pitch, + unsigned int slice_pitch, + size_t *converted_size) +{ + size_t size = width * height * depth * 4; + uint8_t *converted = g_malloc(size); + + for (unsigned int z = 0; z < depth; z++) { + const uint8_t *src_slice = src + z * slice_pitch; + uint8_t *dst_slice = converted + z * width * height * 4; + + for (unsigned int y = 0; y < height; y++) { + const uint8_t *src_row = src_slice + y * row_pitch; + uint8_t *dst_row = dst_slice + y * width * 4; + + for (unsigned int x = 0; x < width; x++) { + uint16_t pixel = lduw_le_p(src_row + x * 2); + uint8_t *out = dst_row + x * 4; + + out[0] = android_vk_expand_5_to_8((pixel >> 10) & 0x1F); + out[1] = android_vk_expand_5_to_8((pixel >> 5) & 0x1F); + out[2] = android_vk_expand_5_to_8(pixel & 0x1F); + out[3] = + (s.color_format == NV097_SET_TEXTURE_FORMAT_COLOR_SZ_X1R5G5B5 || + s.color_format == NV097_SET_TEXTURE_FORMAT_COLOR_LU_IMAGE_X1R5G5B5) ? + 0xFF : + ((pixel & 0x8000) ? 0xFF : 0x00); + } + } + } + + if (converted_size) { + *converted_size = size; + } + return converted; +} +#endif + // FIXME: Move to common // FIXME: We can shrink the size of this structure // FIXME: Use simple allocator @@ -198,6 +260,14 @@ static TextureLayout *get_texture_layout(PGRAPHState *pg, int texture_idx) s, texture_data_ptr, palette_data_ptr, adjusted_width, adjusted_height, 1, adjusted_pitch, 0, &converted_size); +#ifdef __ANDROID__ + if (!converted && android_vk_texture_needs_rgba8_upload(s)) { + converted = android_vk_texture_convert_to_rgba8( + s, texture_data_ptr, adjusted_width, adjusted_height, 1, + adjusted_pitch, 0, &converted_size); + } +#endif + if (!converted) { int dst_stride = adjusted_width * f.bytes_per_pixel; assert(adjusted_width <= s.width); @@ -292,6 +362,14 @@ static TextureLayout *get_texture_layout(PGRAPHState *pg, int texture_idx) s, unswizzled, palette_data_ptr, width, height, 1, pitch, 0, &converted_size); +#ifdef __ANDROID__ + if (!converted && android_vk_texture_needs_rgba8_upload(s)) { + converted = android_vk_texture_convert_to_rgba8( + s, unswizzled, width, height, 1, pitch, 0, + &converted_size); + } +#endif + if (converted) { g_free(unswizzled); } else { @@ -372,6 +450,14 @@ static TextureLayout *get_texture_layout(PGRAPHState *pg, int texture_idx) s, unswizzled, palette_data_ptr, width, height, depth, row_pitch, slice_pitch, &converted_size); +#ifdef __ANDROID__ + if (!converted && android_vk_texture_needs_rgba8_upload(s)) { + converted = android_vk_texture_convert_to_rgba8( + s, unswizzled, width, height, depth, row_pitch, + slice_pitch, &converted_size); + } +#endif + if (converted) { g_free(unswizzled); } else {