Texture region splitting
Introduce the concept of texture regions. Each texture starts with a base region which covers all of its content, and can provide smaller subregions given an offset and size (populated by allocating a new VkImage and blitting from the base region). Subregion allocations and content are cached and invalidated when the base region is written. Writing is only allowed to the base region at this time.
This commit is contained in:
parent
2e3329095b
commit
277b9dd9ae
|
@ -233,12 +233,13 @@ void TextureCache::Shutdown() {
|
||||||
nullptr);
|
nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureCache::Texture* TextureCache::AllocateTexture(
|
TextureCache::TextureRegion* TextureCache::AllocateTextureRegion(
|
||||||
const TextureInfo& texture_info, VkFormatFeatureFlags required_flags) {
|
Texture* texture, VkOffset3D region_offset, VkExtent3D region_size,
|
||||||
|
VkFormatFeatureFlags required_flags) {
|
||||||
// Create an image first.
|
// Create an image first.
|
||||||
VkImageCreateInfo image_info = {};
|
VkImageCreateInfo image_info = {};
|
||||||
image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||||
switch (texture_info.dimension) {
|
switch (texture->texture_info.dimension) {
|
||||||
case Dimension::k1D:
|
case Dimension::k1D:
|
||||||
case Dimension::k2D:
|
case Dimension::k2D:
|
||||||
image_info.imageType = VK_IMAGE_TYPE_2D;
|
image_info.imageType = VK_IMAGE_TYPE_2D;
|
||||||
|
@ -251,36 +252,28 @@ TextureCache::Texture* TextureCache::AllocateTexture(
|
||||||
image_info.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
|
image_info.flags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert_unhandled_case(texture_info.dimension);
|
assert_unhandled_case(texture->texture_info.dimension);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_not_null(texture_info.format_info());
|
|
||||||
auto& config = texture_configs[int(texture_info.format_info()->format)];
|
|
||||||
VkFormat format = config.host_format;
|
|
||||||
assert(format != VK_FORMAT_UNDEFINED);
|
|
||||||
|
|
||||||
image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
|
image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||||
image_info.usage =
|
image_info.usage =
|
||||||
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT;
|
||||||
|
|
||||||
// Check the device limits for the format before we create it.
|
// Check the device limits for the format before we create it.
|
||||||
VkFormatProperties props;
|
VkFormatProperties props;
|
||||||
vkGetPhysicalDeviceFormatProperties(*device_, format, &props);
|
vkGetPhysicalDeviceFormatProperties(*device_, texture->format, &props);
|
||||||
if ((props.optimalTilingFeatures & required_flags) != required_flags) {
|
if ((props.optimalTilingFeatures & required_flags) != required_flags) {
|
||||||
// Texture needs conversion on upload to a native format.
|
// Texture needs conversion on upload to a native format.
|
||||||
XELOGE(
|
XELOGE(
|
||||||
"Texture Cache: Invalid usage flag specified on format %s (%s)\n\t"
|
"Texture Cache: Invalid usage flag specified on format %s (vk %d) "
|
||||||
"(requested: %s)",
|
"(0x%.8X != 0x%.8X)",
|
||||||
texture_info.format_info()->name, ui::vulkan::to_string(format),
|
texture->texture_info.format_info()->name, texture->format,
|
||||||
ui::vulkan::to_flags_string(
|
(props.optimalTilingFeatures & required_flags), required_flags);
|
||||||
static_cast<VkFormatFeatureFlagBits>(required_flags &
|
|
||||||
~props.optimalTilingFeatures))
|
|
||||||
.c_str());
|
|
||||||
assert_always();
|
assert_always();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (texture_info.dimension != Dimension::kCube &&
|
if (texture->texture_info.dimension != Dimension::kCube &&
|
||||||
props.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) {
|
props.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) {
|
||||||
// Add color attachment usage if it's supported.
|
// Add color attachment usage if it's supported.
|
||||||
image_info.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
image_info.usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||||
|
@ -296,43 +289,73 @@ TextureCache::Texture* TextureCache::AllocateTexture(
|
||||||
|
|
||||||
VkImageFormatProperties image_props;
|
VkImageFormatProperties image_props;
|
||||||
vkGetPhysicalDeviceImageFormatProperties(
|
vkGetPhysicalDeviceImageFormatProperties(
|
||||||
*device_, format, image_info.imageType, image_info.tiling,
|
*device_, texture->format, image_info.imageType, image_info.tiling,
|
||||||
image_info.usage, image_info.flags, &image_props);
|
image_info.usage, image_info.flags, &image_props);
|
||||||
|
|
||||||
// TODO(DrChat): Actually check the image properties.
|
// TODO(DrChat): Actually check the image properties.
|
||||||
|
|
||||||
image_info.format = format;
|
image_info.format = texture->format;
|
||||||
image_info.extent = {texture_info.width + 1, texture_info.height + 1, 1};
|
image_info.extent = region_size;
|
||||||
image_info.mipLevels = 1;
|
image_info.mipLevels = 1;
|
||||||
image_info.arrayLayers = texture_info.depth + 1;
|
image_info.arrayLayers = texture->texture_info.depth + 1;
|
||||||
image_info.samples = VK_SAMPLE_COUNT_1_BIT;
|
image_info.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
image_info.queueFamilyIndexCount = 0;
|
image_info.queueFamilyIndexCount = 0;
|
||||||
image_info.pQueueFamilyIndices = nullptr;
|
image_info.pQueueFamilyIndices = nullptr;
|
||||||
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
|
||||||
VkImage image;
|
VkImage image;
|
||||||
|
|
||||||
VmaAllocation alloc;
|
VmaAllocation allocation;
|
||||||
VmaAllocationCreateInfo vma_create_info = {
|
VmaAllocationCreateInfo vma_create_info = {
|
||||||
0, VMA_MEMORY_USAGE_GPU_ONLY, 0, 0, 0, nullptr, nullptr,
|
0, VMA_MEMORY_USAGE_GPU_ONLY, 0, 0, 0, nullptr, nullptr,
|
||||||
};
|
};
|
||||||
VmaAllocationInfo vma_info = {};
|
VmaAllocationInfo vma_info = {};
|
||||||
VkResult status = vmaCreateImage(mem_allocator_, &image_info,
|
VkResult status = vmaCreateImage(mem_allocator_, &image_info, &vma_reqs,
|
||||||
&vma_create_info, &image, &alloc, &vma_info);
|
&image, &allocation, &vma_info);
|
||||||
if (status != VK_SUCCESS) {
|
if (status != VK_SUCCESS) {
|
||||||
// Allocation failed.
|
// Allocation failed.
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextureRegion* region = new TextureRegion();
|
||||||
|
region->texture = texture;
|
||||||
|
|
||||||
|
region->region_offset = region_offset;
|
||||||
|
region->region_size = region_size;
|
||||||
|
|
||||||
|
region->image = image;
|
||||||
|
region->image_layout = image_info.initialLayout;
|
||||||
|
region->allocation = allocation;
|
||||||
|
region->allocation_info = vma_info;
|
||||||
|
|
||||||
|
region->region_contents_valid = false;
|
||||||
|
|
||||||
|
texture->regions.push_back(std::unique_ptr<TextureRegion>(region));
|
||||||
|
return region;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureCache::Texture* TextureCache::AllocateTexture(
|
||||||
|
const TextureInfo& texture_info, VkFormatFeatureFlags required_flags) {
|
||||||
|
VkOffset3D region_offset = {0, 0, 0};
|
||||||
|
VkExtent3D region_extent = {texture_info.width + 1, texture_info.height + 1,
|
||||||
|
1};
|
||||||
|
|
||||||
auto texture = new Texture();
|
auto texture = new Texture();
|
||||||
texture->format = image_info.format;
|
|
||||||
texture->image = image;
|
|
||||||
texture->image_layout = image_info.initialLayout;
|
|
||||||
texture->alloc = alloc;
|
|
||||||
texture->alloc_info = vma_info;
|
|
||||||
texture->framebuffer = nullptr;
|
texture->framebuffer = nullptr;
|
||||||
texture->access_watch_handle = 0;
|
texture->access_watch_handle = 0;
|
||||||
texture->texture_info = texture_info;
|
texture->texture_info = texture_info;
|
||||||
|
|
||||||
|
assert_not_null(texture->texture_info.format_info());
|
||||||
|
auto& config =
|
||||||
|
texture_configs[int(texture->texture_info.format_info()->format)];
|
||||||
|
texture->format = config.host_format != VK_FORMAT_UNDEFINED
|
||||||
|
? config.host_format
|
||||||
|
: VK_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
|
||||||
|
TextureRegion* base_region = AllocateTextureRegion(
|
||||||
|
texture, region_offset, region_extent, required_flags);
|
||||||
|
texture->base_region = base_region;
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,9 +372,14 @@ bool TextureCache::FreeTexture(Texture* texture) {
|
||||||
vkDestroyFramebuffer(*device_, texture->framebuffer, nullptr);
|
vkDestroyFramebuffer(*device_, texture->framebuffer, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto it = texture->views.begin(); it != texture->views.end();) {
|
for (auto region_it = texture->regions.begin();
|
||||||
vkDestroyImageView(*device_, (*it)->view, nullptr);
|
region_it != texture->regions.end(); ++region_it) {
|
||||||
it = texture->views.erase(it);
|
TextureRegion* region = region_it->get();
|
||||||
|
for (auto view_it = region->views.begin(); view_it != region->views.end();
|
||||||
|
++view_it) {
|
||||||
|
vkDestroyImageView(*device_, (*view_it)->view, nullptr);
|
||||||
|
}
|
||||||
|
vmaDestroyImage(mem_allocator_, region->image, region->allocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (texture->access_watch_handle) {
|
if (texture->access_watch_handle) {
|
||||||
|
@ -359,7 +387,6 @@ bool TextureCache::FreeTexture(Texture* texture) {
|
||||||
texture->access_watch_handle = 0;
|
texture->access_watch_handle = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
vmaDestroyImage(mem_allocator_, texture->image, texture->alloc);
|
|
||||||
delete texture;
|
delete texture;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -418,7 +445,7 @@ TextureCache::Texture* TextureCache::DemandResolveTexture(
|
||||||
|
|
||||||
// Setup a debug name for the texture.
|
// Setup a debug name for the texture.
|
||||||
device_->DbgSetObjectName(
|
device_->DbgSetObjectName(
|
||||||
reinterpret_cast<uint64_t>(texture->image),
|
reinterpret_cast<uint64_t>(texture->base_region->image),
|
||||||
VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
|
VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
|
||||||
xe::format_string(
|
xe::format_string(
|
||||||
"0x%.8X - 0x%.8X", texture_info.guest_address,
|
"0x%.8X - 0x%.8X", texture_info.guest_address,
|
||||||
|
@ -434,8 +461,8 @@ TextureCache::Texture* TextureCache::DemandResolveTexture(
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info,
|
TextureCache::TextureRegion* TextureCache::DemandRegion(
|
||||||
VkCommandBuffer command_buffer,
|
const TextureInfo& texture_info, VkCommandBuffer command_buffer,
|
||||||
VkFence completion_fence) {
|
VkFence completion_fence) {
|
||||||
// Run a tight loop to scan for an exact match existing texture.
|
// Run a tight loop to scan for an exact match existing texture.
|
||||||
auto texture_hash = texture_info.hash();
|
auto texture_hash = texture_info.hash();
|
||||||
|
@ -450,7 +477,7 @@ TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info,
|
||||||
trace_writer_->WriteMemoryReadCached(texture_info.guest_address,
|
trace_writer_->WriteMemoryReadCached(texture_info.guest_address,
|
||||||
texture_info.input_length);
|
texture_info.input_length);
|
||||||
|
|
||||||
return it->second;
|
return it->second->base_region;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -460,8 +487,102 @@ TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we didn't find an exact match, see if we can find a subregion of an
|
||||||
|
// existing texture to use.
|
||||||
|
VkOffset2D offset;
|
||||||
|
auto containing_tex = LookupAddress(
|
||||||
|
texture_info.guest_address, texture_info.width + 1,
|
||||||
|
texture_info.height + 1, texture_info.format_info()->format, &offset);
|
||||||
|
if (containing_tex != nullptr) {
|
||||||
|
// Found a larger texture that contains the requested texels.
|
||||||
|
// Find/create/update a matching subregion.
|
||||||
|
|
||||||
|
// First, see if the region exists
|
||||||
|
TextureRegion* region = nullptr;
|
||||||
|
for (auto region_it = containing_tex->regions.begin();
|
||||||
|
region_it != containing_tex->regions.end(); ++region_it) {
|
||||||
|
const VkOffset3D& roffset = (*region_it)->region_offset;
|
||||||
|
const VkExtent3D& rsize = (*region_it)->region_size;
|
||||||
|
if (roffset.x == offset.x && roffset.y == offset.y &&
|
||||||
|
rsize.width == (texture_info.width + 1) &&
|
||||||
|
rsize.height == (texture_info.height + 1)) {
|
||||||
|
// Match found
|
||||||
|
region = region_it->get();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!region) {
|
||||||
|
// No match, create a new region and add it the texture
|
||||||
|
region = AllocateTextureRegion(
|
||||||
|
containing_tex, {offset.x, offset.y, 0},
|
||||||
|
{texture_info.width + 1, texture_info.height + 1, 1},
|
||||||
|
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!region->region_contents_valid) {
|
||||||
|
// Region content is out-of-date, recreate it by blitting from the base
|
||||||
|
// region.
|
||||||
|
|
||||||
|
// Transition the region into a transfer destination layout.
|
||||||
|
VkImageMemoryBarrier barrier;
|
||||||
|
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||||
|
barrier.pNext = nullptr;
|
||||||
|
barrier.srcAccessMask = 0;
|
||||||
|
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
|
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
|
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||||
|
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
|
barrier.image = region->image;
|
||||||
|
barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
||||||
|
if (containing_tex->format == VK_FORMAT_D16_UNORM_S8_UINT ||
|
||||||
|
containing_tex->format == VK_FORMAT_D24_UNORM_S8_UINT ||
|
||||||
|
containing_tex->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);
|
||||||
|
|
||||||
|
// Now move the converted texture into the destination.
|
||||||
|
VkImageCopy copy_region;
|
||||||
|
|
||||||
|
copy_region.srcSubresource = {barrier.subresourceRange.aspectMask, 0, 0,
|
||||||
|
1};
|
||||||
|
copy_region.dstSubresource = {barrier.subresourceRange.aspectMask, 0, 0,
|
||||||
|
1};
|
||||||
|
copy_region.srcOffset = {offset.x, offset.y, 0};
|
||||||
|
copy_region.dstOffset = {0, 0, 0};
|
||||||
|
copy_region.extent = {texture_info.width + 1, texture_info.height + 1, 1};
|
||||||
|
|
||||||
|
vkCmdCopyImage(command_buffer, containing_tex->base_region->image,
|
||||||
|
containing_tex->base_region->image_layout, region->image,
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©_region);
|
||||||
|
|
||||||
|
// Now transition the region into a shader readonly source.
|
||||||
|
barrier.srcAccessMask = barrier.dstAccessMask;
|
||||||
|
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
|
barrier.oldLayout = barrier.newLayout;
|
||||||
|
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||||
|
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||||
|
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0,
|
||||||
|
nullptr, 1, &barrier);
|
||||||
|
|
||||||
|
region->image_layout = barrier.newLayout;
|
||||||
|
|
||||||
|
// Mark contents as up-to-date
|
||||||
|
region->region_contents_valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return region;
|
||||||
|
}
|
||||||
|
|
||||||
// Create a new texture and cache it.
|
// Create a new texture and cache it.
|
||||||
auto texture = AllocateTexture(texture_info);
|
auto texture =
|
||||||
|
AllocateTexture(texture_info, VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
|
||||||
if (!texture) {
|
if (!texture) {
|
||||||
// Failed to allocate texture (out of memory?)
|
// Failed to allocate texture (out of memory?)
|
||||||
assert_always();
|
assert_always();
|
||||||
|
@ -469,18 +590,6 @@ TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Though we didn't find an exact match, that doesn't mean we're out of the
|
|
||||||
// woods yet. This texture could either be a portion of another texture or
|
|
||||||
// vice versa. Copy any overlapping textures into this texture.
|
|
||||||
// TODO: Byte count -> pixel count (on x and y axes)
|
|
||||||
VkOffset2D offset;
|
|
||||||
auto collide_tex = LookupAddress(
|
|
||||||
texture_info.guest_address, texture_info.width + 1,
|
|
||||||
texture_info.height + 1, texture_info.format_info()->format, &offset);
|
|
||||||
if (collide_tex != nullptr) {
|
|
||||||
// assert_always();
|
|
||||||
}
|
|
||||||
|
|
||||||
trace_writer_->WriteMemoryRead(texture_info.guest_address,
|
trace_writer_->WriteMemoryRead(texture_info.guest_address,
|
||||||
texture_info.input_length);
|
texture_info.input_length);
|
||||||
|
|
||||||
|
@ -497,7 +606,7 @@ TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info,
|
||||||
|
|
||||||
// Setup a debug name for the texture.
|
// Setup a debug name for the texture.
|
||||||
device_->DbgSetObjectName(
|
device_->DbgSetObjectName(
|
||||||
reinterpret_cast<uint64_t>(texture->image),
|
reinterpret_cast<uint64_t>(texture->base_region->image),
|
||||||
VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
|
VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
|
||||||
xe::format_string(
|
xe::format_string(
|
||||||
"0x%.8X - 0x%.8X", texture_info.guest_address,
|
"0x%.8X - 0x%.8X", texture_info.guest_address,
|
||||||
|
@ -505,12 +614,12 @@ TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info,
|
||||||
|
|
||||||
textures_[texture_hash] = texture;
|
textures_[texture_hash] = texture;
|
||||||
COUNT_profile_set("gpu/texture_cache/textures", textures_.size());
|
COUNT_profile_set("gpu/texture_cache/textures", textures_.size());
|
||||||
return texture;
|
return texture->base_region;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureCache::TextureView* TextureCache::DemandView(Texture* texture,
|
TextureCache::TextureRegionView* TextureCache::DemandTextureRegionView(
|
||||||
uint16_t swizzle) {
|
TextureRegion* region, uint16_t swizzle) {
|
||||||
for (auto it = texture->views.begin(); it != texture->views.end(); ++it) {
|
for (auto it = region->views.begin(); it != region->views.end(); ++it) {
|
||||||
if ((*it)->swizzle == swizzle) {
|
if ((*it)->swizzle == swizzle) {
|
||||||
return (*it).get();
|
return (*it).get();
|
||||||
}
|
}
|
||||||
|
@ -520,10 +629,10 @@ TextureCache::TextureView* TextureCache::DemandView(Texture* texture,
|
||||||
view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||||
view_info.pNext = nullptr;
|
view_info.pNext = nullptr;
|
||||||
view_info.flags = 0;
|
view_info.flags = 0;
|
||||||
view_info.image = texture->image;
|
view_info.image = region->image;
|
||||||
view_info.format = texture->format;
|
view_info.format = region->texture->format;
|
||||||
|
|
||||||
switch (texture->texture_info.dimension) {
|
switch (region->texture->texture_info.dimension) {
|
||||||
case Dimension::k1D:
|
case Dimension::k1D:
|
||||||
case Dimension::k2D:
|
case Dimension::k2D:
|
||||||
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||||
|
@ -552,14 +661,14 @@ TextureCache::TextureView* TextureCache::DemandView(Texture* texture,
|
||||||
swiz_component_map[(swizzle >> 9) & 0x7],
|
swiz_component_map[(swizzle >> 9) & 0x7],
|
||||||
};
|
};
|
||||||
view_info.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
view_info.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
||||||
if (texture->format == VK_FORMAT_D16_UNORM_S8_UINT ||
|
if (region->texture->format == VK_FORMAT_D16_UNORM_S8_UINT ||
|
||||||
texture->format == VK_FORMAT_D24_UNORM_S8_UINT ||
|
region->texture->format == VK_FORMAT_D24_UNORM_S8_UINT ||
|
||||||
texture->format == VK_FORMAT_D32_SFLOAT_S8_UINT) {
|
region->texture->format == VK_FORMAT_D32_SFLOAT_S8_UINT) {
|
||||||
// This applies to any depth/stencil format, but we only use D24S8 / D32FS8.
|
// This applies to any depth/stencil format, but we only use D24S8 / D32FS8.
|
||||||
view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (texture->texture_info.dimension == Dimension::kCube) {
|
if (region->texture->texture_info.dimension == Dimension::kCube) {
|
||||||
view_info.subresourceRange.layerCount = 6;
|
view_info.subresourceRange.layerCount = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -567,12 +676,12 @@ TextureCache::TextureView* TextureCache::DemandView(Texture* texture,
|
||||||
auto status = vkCreateImageView(*device_, &view_info, nullptr, &view);
|
auto status = vkCreateImageView(*device_, &view_info, nullptr, &view);
|
||||||
CheckResult(status, "vkCreateImageView");
|
CheckResult(status, "vkCreateImageView");
|
||||||
if (status == VK_SUCCESS) {
|
if (status == VK_SUCCESS) {
|
||||||
auto texture_view = new TextureView();
|
auto region_view = new TextureRegionView();
|
||||||
texture_view->texture = texture;
|
region_view->region = region;
|
||||||
texture_view->view = view;
|
region_view->view = view;
|
||||||
texture_view->swizzle = swizzle;
|
region_view->swizzle = swizzle;
|
||||||
texture->views.push_back(std::unique_ptr<TextureView>(texture_view));
|
region->views.push_back(std::unique_ptr<TextureRegionView>(region_view));
|
||||||
return texture_view;
|
return region_view;
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -1115,7 +1224,8 @@ bool TextureCache::ComputeTextureStorage(size_t* output_length,
|
||||||
void TextureCache::WritebackTexture(Texture* texture) {
|
void TextureCache::WritebackTexture(Texture* texture) {
|
||||||
VkResult status = VK_SUCCESS;
|
VkResult status = VK_SUCCESS;
|
||||||
VkFence fence = wb_command_pool_->BeginBatch();
|
VkFence fence = wb_command_pool_->BeginBatch();
|
||||||
auto alloc = wb_staging_buffer_.Acquire(texture->alloc_info.size, fence);
|
auto alloc = wb_staging_buffer_.Acquire(
|
||||||
|
texture->base_region->allocation_info.size, fence);
|
||||||
if (!alloc) {
|
if (!alloc) {
|
||||||
wb_command_pool_->EndBatch();
|
wb_command_pool_->EndBatch();
|
||||||
return;
|
return;
|
||||||
|
@ -1142,7 +1252,7 @@ void TextureCache::WritebackTexture(Texture* texture) {
|
||||||
{texture->texture_info.width + 1, texture->texture_info.height + 1, 1},
|
{texture->texture_info.width + 1, texture->texture_info.height + 1, 1},
|
||||||
};
|
};
|
||||||
|
|
||||||
vkCmdCopyImageToBuffer(command_buffer, texture->image,
|
vkCmdCopyImageToBuffer(command_buffer, texture->base_region->image,
|
||||||
VK_IMAGE_LAYOUT_GENERAL,
|
VK_IMAGE_LAYOUT_GENERAL,
|
||||||
wb_staging_buffer_.gpu_buffer(), 1, ®ion);
|
wb_staging_buffer_.gpu_buffer(), 1, ®ion);
|
||||||
|
|
||||||
|
@ -1235,6 +1345,14 @@ bool TextureCache::UploadTexture(VkCommandBuffer command_buffer,
|
||||||
src.guest_address, src.input_length, src.texture_format);
|
src.guest_address, src.input_length, src.texture_format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Invalidate contents of all regions for this texture, except for the base
|
||||||
|
// region.
|
||||||
|
for (auto region_it = dest->regions.begin(); region_it != dest->regions.end();
|
||||||
|
++region_it) {
|
||||||
|
(*region_it)->region_contents_valid = false;
|
||||||
|
}
|
||||||
|
dest->base_region->region_contents_valid = true;
|
||||||
|
|
||||||
// Upload texture into GPU memory.
|
// Upload texture into GPU memory.
|
||||||
// TODO: If the GPU supports it, we can submit a compute batch to convert the
|
// TODO: If the GPU supports it, we can submit a compute batch to convert the
|
||||||
// texture and copy it to its destination. Otherwise, fallback to conversion
|
// texture and copy it to its destination. Otherwise, fallback to conversion
|
||||||
|
@ -1252,11 +1370,11 @@ bool TextureCache::UploadTexture(VkCommandBuffer command_buffer,
|
||||||
barrier.pNext = nullptr;
|
barrier.pNext = nullptr;
|
||||||
barrier.srcAccessMask = 0;
|
barrier.srcAccessMask = 0;
|
||||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
barrier.oldLayout = dest->image_layout;
|
barrier.oldLayout = dest->base_region->image_layout;
|
||||||
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
|
||||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
barrier.image = dest->image;
|
barrier.image = dest->base_region->image;
|
||||||
barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1,
|
barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1,
|
||||||
copy_region.imageSubresource.baseArrayLayer,
|
copy_region.imageSubresource.baseArrayLayer,
|
||||||
copy_region.imageSubresource.layerCount};
|
copy_region.imageSubresource.layerCount};
|
||||||
|
@ -1281,8 +1399,8 @@ bool TextureCache::UploadTexture(VkCommandBuffer command_buffer,
|
||||||
copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||||
}
|
}
|
||||||
vkCmdCopyBufferToImage(command_buffer, staging_buffer_.gpu_buffer(),
|
vkCmdCopyBufferToImage(command_buffer, staging_buffer_.gpu_buffer(),
|
||||||
dest->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1,
|
dest->base_region->image,
|
||||||
©_region);
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©_region);
|
||||||
|
|
||||||
// Now transition the texture into a shader readonly source.
|
// Now transition the texture into a shader readonly source.
|
||||||
barrier.srcAccessMask = barrier.dstAccessMask;
|
barrier.srcAccessMask = barrier.dstAccessMask;
|
||||||
|
@ -1294,7 +1412,7 @@ bool TextureCache::UploadTexture(VkCommandBuffer command_buffer,
|
||||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||||
0, 0, nullptr, 0, nullptr, 1, &barrier);
|
0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||||
|
|
||||||
dest->image_layout = barrier.newLayout;
|
dest->base_region->image_layout = barrier.newLayout;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1435,14 +1553,15 @@ bool TextureCache::SetupTextureBinding(VkCommandBuffer command_buffer,
|
||||||
// Search via the base format.
|
// Search via the base format.
|
||||||
texture_info.texture_format = GetBaseFormat(texture_info.texture_format);
|
texture_info.texture_format = GetBaseFormat(texture_info.texture_format);
|
||||||
|
|
||||||
auto texture = Demand(texture_info, command_buffer, completion_fence);
|
auto texture_region =
|
||||||
|
DemandRegion(texture_info, command_buffer, completion_fence);
|
||||||
auto sampler = Demand(sampler_info);
|
auto sampler = Demand(sampler_info);
|
||||||
if (texture == nullptr || sampler == nullptr) {
|
if (texture_region == nullptr || sampler == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t swizzle = static_cast<uint16_t>(fetch.swizzle);
|
uint16_t swizzle = static_cast<uint16_t>(fetch.swizzle);
|
||||||
auto view = DemandView(texture, swizzle);
|
auto view = DemandTextureRegionView(texture_region, swizzle);
|
||||||
|
|
||||||
auto image_info =
|
auto image_info =
|
||||||
&update_set_info->image_infos[update_set_info->image_write_count];
|
&update_set_info->image_infos[update_set_info->image_write_count];
|
||||||
|
@ -1465,9 +1584,9 @@ bool TextureCache::SetupTextureBinding(VkCommandBuffer command_buffer,
|
||||||
image_write->pTexelBufferView = nullptr;
|
image_write->pTexelBufferView = nullptr;
|
||||||
|
|
||||||
image_info->imageView = view->view;
|
image_info->imageView = view->view;
|
||||||
image_info->imageLayout = texture->image_layout;
|
image_info->imageLayout = texture_region->image_layout;
|
||||||
image_info->sampler = sampler->sampler;
|
image_info->sampler = sampler->sampler;
|
||||||
texture->in_flight_fence = completion_fence;
|
texture_region->texture->in_flight_fence = completion_fence;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,29 +34,11 @@ namespace vulkan {
|
||||||
//
|
//
|
||||||
class TextureCache {
|
class TextureCache {
|
||||||
public:
|
public:
|
||||||
struct TextureView;
|
struct TextureRegion;
|
||||||
|
struct Texture;
|
||||||
|
|
||||||
// This represents an uploaded Vulkan texture.
|
struct TextureRegionView {
|
||||||
struct Texture {
|
TextureRegion* region;
|
||||||
TextureInfo texture_info;
|
|
||||||
std::vector<std::unique_ptr<TextureView>> views;
|
|
||||||
|
|
||||||
VkFormat format;
|
|
||||||
VkImage image;
|
|
||||||
VkImageLayout image_layout;
|
|
||||||
VmaAllocation alloc;
|
|
||||||
VmaAllocationInfo alloc_info;
|
|
||||||
VkFramebuffer framebuffer; // Blit target frame buffer.
|
|
||||||
|
|
||||||
uintptr_t access_watch_handle;
|
|
||||||
bool pending_invalidation;
|
|
||||||
|
|
||||||
// Pointer to the latest usage fence.
|
|
||||||
VkFence in_flight_fence;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TextureView {
|
|
||||||
Texture* texture;
|
|
||||||
VkImageView view;
|
VkImageView view;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@ -73,6 +55,43 @@ class TextureCache {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct TextureRegion {
|
||||||
|
Texture* texture;
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<TextureRegionView>> views;
|
||||||
|
|
||||||
|
VkOffset3D region_offset;
|
||||||
|
VkExtent3D region_size;
|
||||||
|
|
||||||
|
VkImage image;
|
||||||
|
VkImageLayout image_layout;
|
||||||
|
VmaAllocation allocation;
|
||||||
|
VmaAllocationInfo allocation_info;
|
||||||
|
|
||||||
|
bool region_contents_valid;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This represents an uploaded Vulkan texture. A texture has a base image
|
||||||
|
// region containing its full content area, and zero or more regions
|
||||||
|
// that are crops of that base region.
|
||||||
|
struct Texture {
|
||||||
|
TextureInfo texture_info;
|
||||||
|
VkFormat format;
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<TextureRegion>> regions;
|
||||||
|
|
||||||
|
// Non-owning; base region is also in the (owning) regions vector.
|
||||||
|
TextureRegion* base_region;
|
||||||
|
|
||||||
|
VkFramebuffer framebuffer; // Blit target frame buffer.
|
||||||
|
|
||||||
|
uintptr_t access_watch_handle;
|
||||||
|
bool pending_invalidation;
|
||||||
|
|
||||||
|
// Pointer to the latest usage fence.
|
||||||
|
VkFence in_flight_fence;
|
||||||
|
};
|
||||||
|
|
||||||
TextureCache(Memory* memory, RegisterFile* register_file,
|
TextureCache(Memory* memory, RegisterFile* register_file,
|
||||||
TraceWriter* trace_writer, ui::vulkan::VulkanDevice* device);
|
TraceWriter* trace_writer, ui::vulkan::VulkanDevice* device);
|
||||||
~TextureCache();
|
~TextureCache();
|
||||||
|
@ -108,7 +127,7 @@ class TextureCache {
|
||||||
uint32_t height, TextureFormat format,
|
uint32_t height, TextureFormat format,
|
||||||
VkOffset2D* out_offset = nullptr);
|
VkOffset2D* out_offset = nullptr);
|
||||||
|
|
||||||
TextureView* DemandView(Texture* texture, uint16_t swizzle);
|
TextureRegionView* DemandTextureRegionView(TextureRegion*, uint16_t swizzle);
|
||||||
|
|
||||||
// Demands a texture for the purpose of resolving from EDRAM. This either
|
// Demands a texture for the purpose of resolving from EDRAM. This either
|
||||||
// creates a new texture or returns a previously created texture.
|
// creates a new texture or returns a previously created texture.
|
||||||
|
@ -131,16 +150,18 @@ class TextureCache {
|
||||||
|
|
||||||
// Allocates a new texture and memory to back it on the GPU.
|
// 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 =
|
VkFormatFeatureFlags required_flags);
|
||||||
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
|
|
||||||
bool FreeTexture(Texture* texture);
|
bool FreeTexture(Texture* texture);
|
||||||
|
|
||||||
static void WatchCallback(void* context_ptr, void* data_ptr,
|
static void WatchCallback(void* context_ptr, void* data_ptr,
|
||||||
uint32_t address);
|
uint32_t address);
|
||||||
|
TextureRegion* AllocateTextureRegion(Texture*, VkOffset3D region_offset,
|
||||||
|
VkExtent3D region_size,
|
||||||
|
VkFormatFeatureFlags required_flags);
|
||||||
|
|
||||||
// Demands a texture. If command_buffer is null and the texture hasn't been
|
// 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.
|
// uploaded to graphics memory already, we will return null and bail.
|
||||||
Texture* Demand(const TextureInfo& texture_info,
|
TextureRegion* DemandRegion(const TextureInfo& texture_info,
|
||||||
VkCommandBuffer command_buffer = nullptr,
|
VkCommandBuffer command_buffer = nullptr,
|
||||||
VkFence completion_fence = nullptr);
|
VkFence completion_fence = nullptr);
|
||||||
Sampler* Demand(const SamplerInfo& sampler_info);
|
Sampler* Demand(const SamplerInfo& sampler_info);
|
||||||
|
|
|
@ -436,11 +436,11 @@ void VulkanCommandProcessor::PerformSwap(uint32_t frontbuffer_ptr,
|
||||||
barrier.srcAccessMask =
|
barrier.srcAccessMask =
|
||||||
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
|
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||||
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||||
barrier.oldLayout = texture->image_layout;
|
barrier.oldLayout = texture->base_region->image_layout;
|
||||||
barrier.newLayout = texture->image_layout;
|
barrier.newLayout = texture->base_region->image_layout;
|
||||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||||
barrier.image = texture->image;
|
barrier.image = texture->base_region->image;
|
||||||
barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
barrier.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
|
||||||
|
|
||||||
vkCmdPipelineBarrier(copy_commands,
|
vkCmdPipelineBarrier(copy_commands,
|
||||||
|
@ -473,7 +473,9 @@ void VulkanCommandProcessor::PerformSwap(uint32_t frontbuffer_ptr,
|
||||||
|
|
||||||
blitter_->BlitTexture2D(
|
blitter_->BlitTexture2D(
|
||||||
copy_commands, current_batch_fence_,
|
copy_commands, current_batch_fence_,
|
||||||
texture_cache_->DemandView(texture, 0x688)->view, src_rect,
|
texture_cache_->DemandTextureRegionView(texture->base_region, 0x688)
|
||||||
|
->view,
|
||||||
|
src_rect,
|
||||||
{texture->texture_info.width + 1, texture->texture_info.height + 1},
|
{texture->texture_info.width + 1, texture->texture_info.height + 1},
|
||||||
VK_FORMAT_R8G8B8A8_UNORM, dst_rect,
|
VK_FORMAT_R8G8B8A8_UNORM, dst_rect,
|
||||||
{frontbuffer_width, frontbuffer_height}, fb_framebuffer_, viewport,
|
{frontbuffer_width, frontbuffer_height}, fb_framebuffer_, viewport,
|
||||||
|
@ -825,7 +827,7 @@ bool VulkanCommandProcessor::PopulateSamplers(VkCommandBuffer command_buffer,
|
||||||
|
|
||||||
std::vector<xe::gpu::Shader::TextureBinding> dummy_bindings;
|
std::vector<xe::gpu::Shader::TextureBinding> dummy_bindings;
|
||||||
auto descriptor_set = texture_cache_->PrepareTextureSet(
|
auto descriptor_set = texture_cache_->PrepareTextureSet(
|
||||||
setup_buffer, current_batch_fence_, vertex_shader->texture_bindings(),
|
command_buffer, current_batch_fence_, vertex_shader->texture_bindings(),
|
||||||
pixel_shader ? pixel_shader->texture_bindings() : dummy_bindings);
|
pixel_shader ? pixel_shader->texture_bindings() : dummy_bindings);
|
||||||
if (!descriptor_set) {
|
if (!descriptor_set) {
|
||||||
// Unable to bind set.
|
// Unable to bind set.
|
||||||
|
@ -1039,7 +1041,15 @@ bool VulkanCommandProcessor::IssueCopy() {
|
||||||
}
|
}
|
||||||
auto command_buffer = current_command_buffer_;
|
auto command_buffer = current_command_buffer_;
|
||||||
|
|
||||||
if (texture->image_layout == VK_IMAGE_LAYOUT_UNDEFINED) {
|
// Mark all regions of the texture (except base region, which we will write
|
||||||
|
// to) as invalid
|
||||||
|
for (auto region_it = texture->regions.begin();
|
||||||
|
region_it != texture->regions.end(); ++region_it) {
|
||||||
|
(*region_it)->region_contents_valid = false;
|
||||||
|
}
|
||||||
|
texture->base_region->region_contents_valid = true;
|
||||||
|
|
||||||
|
if (texture->base_region->image_layout == VK_IMAGE_LAYOUT_UNDEFINED) {
|
||||||
// Transition the image to a general layout.
|
// Transition the image to a general layout.
|
||||||
VkImageMemoryBarrier image_barrier;
|
VkImageMemoryBarrier image_barrier;
|
||||||
image_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
image_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||||
|
@ -1050,13 +1060,13 @@ bool VulkanCommandProcessor::IssueCopy() {
|
||||||
image_barrier.dstAccessMask = 0;
|
image_barrier.dstAccessMask = 0;
|
||||||
image_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
image_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||||
image_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
|
image_barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
image_barrier.image = texture->image;
|
image_barrier.image = texture->base_region->image;
|
||||||
image_barrier.subresourceRange = {0, 0, 1, 0, 1};
|
image_barrier.subresourceRange = {0, 0, 1, 0, 1};
|
||||||
image_barrier.subresourceRange.aspectMask =
|
image_barrier.subresourceRange.aspectMask =
|
||||||
is_color_source
|
is_color_source
|
||||||
? VK_IMAGE_ASPECT_COLOR_BIT
|
? VK_IMAGE_ASPECT_COLOR_BIT
|
||||||
: VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
|
: VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||||
texture->image_layout = VK_IMAGE_LAYOUT_GENERAL;
|
texture->base_region->image_layout = VK_IMAGE_LAYOUT_GENERAL;
|
||||||
|
|
||||||
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||||
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0,
|
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0,
|
||||||
|
@ -1074,11 +1084,11 @@ bool VulkanCommandProcessor::IssueCopy() {
|
||||||
image_barrier.dstAccessMask =
|
image_barrier.dstAccessMask =
|
||||||
is_color_source ? VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
|
is_color_source ? VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT
|
||||||
: VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
: VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||||
image_barrier.oldLayout = texture->image_layout;
|
image_barrier.oldLayout = texture->base_region->image_layout;
|
||||||
image_barrier.newLayout =
|
image_barrier.newLayout =
|
||||||
is_color_source ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
|
is_color_source ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL
|
||||||
: VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
: VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||||
image_barrier.image = texture->image;
|
image_barrier.image = texture->base_region->image;
|
||||||
image_barrier.subresourceRange = {0, 0, 1, 0, 1};
|
image_barrier.subresourceRange = {0, 0, 1, 0, 1};
|
||||||
image_barrier.subresourceRange.aspectMask =
|
image_barrier.subresourceRange.aspectMask =
|
||||||
is_color_source ? VK_IMAGE_ASPECT_COLOR_BIT
|
is_color_source ? VK_IMAGE_ASPECT_COLOR_BIT
|
||||||
|
@ -1152,7 +1162,8 @@ bool VulkanCommandProcessor::IssueCopy() {
|
||||||
|
|
||||||
// Create a framebuffer containing our image.
|
// Create a framebuffer containing our image.
|
||||||
if (!texture->framebuffer) {
|
if (!texture->framebuffer) {
|
||||||
auto texture_view = texture_cache_->DemandView(texture, 0x688);
|
auto texture_view = texture_cache_->DemandTextureRegionView(
|
||||||
|
texture->base_region, 0x688);
|
||||||
|
|
||||||
VkFramebufferCreateInfo fb_create_info = {
|
VkFramebufferCreateInfo fb_create_info = {
|
||||||
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
||||||
|
|
Loading…
Reference in New Issue