Skip to content

Commit

Permalink
Vulkan CP: Use the color blitter
Browse files Browse the repository at this point in the history
  • Loading branch information
DrChat committed May 13, 2017
1 parent a41cf1a commit 84758a3
Show file tree
Hide file tree
Showing 7 changed files with 268 additions and 69 deletions.
41 changes: 34 additions & 7 deletions src/xenia/gpu/vulkan/render_cache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -236,16 +236,27 @@ CachedTileView::CachedTileView(ui::vulkan::VulkanDevice* device,
err = vkCreateImageView(device_, &image_view_info, nullptr, &image_view);
CheckResult(err, "vkCreateImageView");

// Create separate depth/stencil views.
if (key.color_or_depth == 0) {
image_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
err = vkCreateImageView(device_, &image_view_info, nullptr,
&image_view_depth);
CheckResult(err, "vkCreateImageView");

image_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
err = vkCreateImageView(device_, &image_view_info, nullptr,
&image_view_depth);
CheckResult(err, "vkCreateImageView");
}

// TODO(benvanik): transition to general layout?
VkImageMemoryBarrier image_barrier;
image_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
image_barrier.pNext = nullptr;
image_barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
image_barrier.srcAccessMask = 0;
image_barrier.dstAccessMask =
key.color_or_depth ? VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
: VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
image_barrier.dstAccessMask |=
VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
image_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
image_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
image_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
Expand Down Expand Up @@ -873,12 +884,28 @@ bool RenderCache::ConfigureRenderPass(VkCommandBuffer command_buffer,
return true;
}

VkImageView RenderCache::FindTileView(uint32_t base, uint32_t pitch,
MsaaSamples samples, bool color_or_depth,
uint32_t format) {
CachedTileView* RenderCache::FindTileView(uint32_t base, uint32_t pitch,
MsaaSamples samples,
bool color_or_depth,
uint32_t format) {
uint32_t tile_width = samples == MsaaSamples::k4X ? 40 : 80;
uint32_t tile_height = samples != MsaaSamples::k1X ? 8 : 16;

if (color_or_depth) {
// Adjust similar formats for easier matching.
switch (static_cast<ColorRenderTargetFormat>(format)) {
case ColorRenderTargetFormat::k_8_8_8_8_GAMMA:
format = uint32_t(ColorRenderTargetFormat::k_8_8_8_8);
break;
case ColorRenderTargetFormat::k_2_10_10_10_unknown:
format = uint32_t(ColorRenderTargetFormat::k_2_10_10_10);
break;
case ColorRenderTargetFormat::k_2_10_10_10_FLOAT_unknown:
format = uint32_t(ColorRenderTargetFormat::k_2_10_10_10_FLOAT);
break;
}
}

TileViewKey key;
key.tile_offset = base;
key.tile_width = xe::round_up(pitch, tile_width) / tile_width;
Expand All @@ -888,7 +915,7 @@ VkImageView RenderCache::FindTileView(uint32_t base, uint32_t pitch,
key.edram_format = static_cast<uint16_t>(format);
auto view = FindTileView(key);
if (view) {
return view->image_view;
return view;
}

return nullptr;
Expand Down
14 changes: 12 additions & 2 deletions src/xenia/gpu/vulkan/render_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ class CachedTileView {
// Image sample count
VkSampleCountFlagBits sample_count = VK_SAMPLE_COUNT_1_BIT;

// (if a depth view) Image view of depth aspect
VkImageView image_view_depth = nullptr;
// (if a depth view) Image view of stencil aspect
VkImageView image_view_stencil = nullptr;

CachedTileView(ui::vulkan::VulkanDevice* device,
VkCommandBuffer command_buffer, VkDeviceMemory edram_memory,
TileViewKey view_key);
Expand All @@ -76,6 +81,10 @@ class CachedTileView {
return key.tile_offset < other.key.tile_offset;
}

VkExtent2D GetSize() const {
return {key.tile_width * 80ul, key.tile_height * 16ul};
}

private:
VkDevice device_ = nullptr;
};
Expand Down Expand Up @@ -269,8 +278,9 @@ class RenderCache {
// with an already open pass.
bool dirty() const;

VkImageView FindTileView(uint32_t base, uint32_t pitch, MsaaSamples samples,
bool color_or_depth, uint32_t format);
CachedTileView* FindTileView(uint32_t base, uint32_t pitch,
MsaaSamples samples, bool color_or_depth,
uint32_t format);

// Begins a render pass targeting the state-specified framebuffer formats.
// The command buffer will be transitioned into the render pass phase.
Expand Down
68 changes: 47 additions & 21 deletions src/xenia/gpu/vulkan/texture_cache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ void TextureCache::DestroyEmptySet() {
}

TextureCache::Texture* TextureCache::AllocateTexture(
const TextureInfo& texture_info) {
const TextureInfo& texture_info, VkFormatFeatureFlags required_flags) {
// Create an image first.
VkImageCreateInfo image_info = {};
image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
Expand Down Expand Up @@ -341,18 +341,24 @@ TextureCache::Texture* TextureCache::AllocateTexture(
: VK_FORMAT_R8G8B8A8_UNORM;

image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
image_info.usage = VK_IMAGE_USAGE_SAMPLED_BIT |
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT;
image_info.usage =
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;

// Check the device limits for the format before we create it.
VkFormatProperties props;
vkGetPhysicalDeviceFormatProperties(*device_, format, &props);
uint32_t required_flags =
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_BLIT_SRC_BIT;
if ((props.optimalTilingFeatures & required_flags) != required_flags) {
// Texture needs conversion on upload to a native format.
// assert_always();
assert_always();
}

if (props.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) {
// Add color attachment usage if it's supported.
image_info.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
}

if (props.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT) {
image_info.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
}

VkImageFormatProperties image_props;
Expand Down Expand Up @@ -413,6 +419,10 @@ bool TextureCache::FreeTexture(Texture* texture) {
return false;
}

if (texture->framebuffer) {
vkDestroyFramebuffer(*device_, texture->framebuffer, nullptr);
}

for (auto it = texture->views.begin(); it != texture->views.end();) {
vkDestroyImageView(*device_, (*it)->view, nullptr);
it = texture->views.erase(it);
Expand Down Expand Up @@ -449,7 +459,9 @@ TextureCache::Texture* TextureCache::DemandResolveTexture(
}

// No texture at this location. Make a new one.
auto texture = AllocateTexture(texture_info);
auto texture =
AllocateTexture(texture_info, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT);

// Setup a debug name for the texture.
device_->DbgSetObjectName(
Expand Down Expand Up @@ -965,23 +977,30 @@ void TextureCache::ConvertTexture2D(uint8_t* dest, const TextureInfo& src) {
uint32_t offset_x;
uint32_t offset_y;
TextureInfo::GetPackedTileOffset(src, &offset_x, &offset_y);
auto bpp = (bytes_per_block >> 2) +
((bytes_per_block >> 1) >> (bytes_per_block >> 2));
for (uint32_t y = 0, output_base_offset = 0;
y < std::min(src.size_2d.block_height, src.size_2d.logical_height);
y++, output_base_offset += src.size_2d.output_pitch) {
auto input_base_offset = TextureInfo::TiledOffset2DOuter(
offset_y + y,
(src.size_2d.input_width / src.format_info()->block_width), bpp);
for (uint32_t x = 0, output_offset = output_base_offset;
x < src.size_2d.block_width; x++, output_offset += bytes_per_block) {
auto log2_bpp = (bytes_per_block >> 2) +
((bytes_per_block >> 1) >> (bytes_per_block >> 2));

// Offset to the current row, in bytes.
uint32_t output_row_offset = 0;
for (uint32_t y = 0; y < src.size_2d.block_height; y++) {
auto input_row_offset = TextureInfo::TiledOffset2DOuter(
offset_y + y, src.size_2d.block_width, log2_bpp);

// Go block-by-block on this row.
uint32_t output_offset = output_row_offset;
for (uint32_t x = 0; x < src.size_2d.block_width; x++) {
auto input_offset =
TextureInfo::TiledOffset2DInner(offset_x + x, offset_y + y, bpp,
input_base_offset) >>
bpp;
TextureInfo::TiledOffset2DInner(offset_x + x, offset_y + y,
log2_bpp, input_row_offset) >>
log2_bpp;

TextureSwap(src.endianness, dest + output_offset,
src_mem + input_offset * bytes_per_block, bytes_per_block);

output_offset += bytes_per_block;
}

output_row_offset += src.size_2d.output_pitch;
}
}
}
Expand Down Expand Up @@ -1174,6 +1193,13 @@ bool TextureCache::UploadTexture2D(VkCommandBuffer command_buffer,
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.image = dest->image;
barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
if (dest->format == VK_FORMAT_D16_UNORM_S8_UINT ||
dest->format == VK_FORMAT_D24_UNORM_S8_UINT ||
dest->format == VK_FORMAT_D32_SFLOAT_S8_UINT) {
barrier.subresourceRange.aspectMask =
VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
}

vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0,
nullptr, 1, &barrier);
Expand Down
8 changes: 6 additions & 2 deletions src/xenia/gpu/vulkan/texture_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class TextureCache {
VkDeviceMemory image_memory;
VkDeviceSize memory_offset;
VkDeviceSize memory_size;
VkFramebuffer framebuffer; // Blit target frame buffer.

uintptr_t access_watch_handle;
bool pending_invalidation;
Expand Down Expand Up @@ -100,6 +101,8 @@ class TextureCache {
uint32_t height, TextureFormat format,
VkOffset2D* out_offset = nullptr);

TextureView* DemandView(Texture* texture, uint16_t swizzle);

// Demands a texture for the purpose of resolving from EDRAM. This either
// creates a new texture or returns a previously created texture.
Texture* DemandResolveTexture(const TextureInfo& texture_info,
Expand All @@ -124,15 +127,16 @@ class TextureCache {
void DestroyEmptySet();

// Allocates a new texture and memory to back it on the GPU.
Texture* AllocateTexture(const TextureInfo& texture_info);
Texture* AllocateTexture(const TextureInfo& texture_info,
VkFormatFeatureFlags required_flags =
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
bool FreeTexture(Texture* texture);

// Demands a texture. If command_buffer is null and the texture hasn't been
// uploaded to graphics memory already, we will return null and bail.
Texture* Demand(const TextureInfo& texture_info,
VkCommandBuffer command_buffer = nullptr,
VkFence completion_fence = nullptr);
TextureView* DemandView(Texture* texture, uint16_t swizzle);
Sampler* Demand(const SamplerInfo& sampler_info);

void FlushPendingCommands(VkCommandBuffer command_buffer,
Expand Down
Loading

2 comments on commit 84758a3

@Parovozik
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi. This great! Now many games on Vulkan have correct colors :)
I tried
-sonic 2006
-asterix at the olympic games
-bully
-ice age 3 dawn of the dinosaurus
-dynasty warriors 6 empires
Thanks so much!

@AmbientMalice
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect Dark has correct colours in Vulkan now. (Geometry is still a garbled mess, though.)

Please sign in to comment.