[Vulkan] Frontbuffer presentation
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -265,6 +265,9 @@ class VulkanCommandProcessor : public CommandProcessor {
|
||||
|
||||
void WriteRegister(uint32_t index, uint32_t value) override;
|
||||
|
||||
void OnGammaRamp256EntryTableValueWritten() override;
|
||||
void OnGammaRampPWLValueWritten() override;
|
||||
|
||||
void IssueSwap(uint32_t frontbuffer_ptr, uint32_t frontbuffer_width,
|
||||
uint32_t frontbuffer_height) override;
|
||||
|
||||
@@ -398,6 +401,21 @@ class VulkanCommandProcessor : public CommandProcessor {
|
||||
VkDescriptorSet set;
|
||||
};
|
||||
|
||||
enum SwapApplyGammaDescriptorSet : uint32_t {
|
||||
kSwapApplyGammaDescriptorSetRamp,
|
||||
kSwapApplyGammaDescriptorSetSource,
|
||||
|
||||
kSwapApplyGammaDescriptorSetCount,
|
||||
};
|
||||
|
||||
// Framebuffer for the current presenter's guest output image revision, and
|
||||
// its usage tracking.
|
||||
struct SwapFramebuffer {
|
||||
VkFramebuffer framebuffer = VK_NULL_HANDLE;
|
||||
uint64_t version = UINT64_MAX;
|
||||
uint64_t last_submission = 0;
|
||||
};
|
||||
|
||||
// BeginSubmission and EndSubmission may be called at any time. If there's an
|
||||
// open non-frame submission, BeginSubmission(true) will promote it to a
|
||||
// frame. EndSubmission(true) will close the frame no matter whether the
|
||||
@@ -554,24 +572,55 @@ class VulkanCommandProcessor : public CommandProcessor {
|
||||
VkDescriptorPool shared_memory_and_edram_descriptor_pool_ = VK_NULL_HANDLE;
|
||||
VkDescriptorSet shared_memory_and_edram_descriptor_set_;
|
||||
|
||||
// Bytes 0x0...0x3FF - 256-entry gamma ramp table with B10G10R10X2 data (read
|
||||
// as R10G10B10X2 with swizzle).
|
||||
// Bytes 0x400...0x9FF - 128-entry PWL R16G16 gamma ramp (R - base, G - delta,
|
||||
// low 6 bits of each are zero, 3 elements per entry).
|
||||
// kMaxFramesInFlight pairs of gamma ramps if in host-visible memory and
|
||||
// uploaded directly, one otherwise.
|
||||
VkDeviceMemory gamma_ramp_buffer_memory_ = VK_NULL_HANDLE;
|
||||
VkBuffer gamma_ramp_buffer_ = VK_NULL_HANDLE;
|
||||
// kMaxFramesInFlight pairs, only when the gamma ramp buffer is not
|
||||
// host-visible.
|
||||
VkDeviceMemory gamma_ramp_upload_buffer_memory_ = VK_NULL_HANDLE;
|
||||
VkBuffer gamma_ramp_upload_buffer_ = VK_NULL_HANDLE;
|
||||
VkDeviceSize gamma_ramp_upload_memory_size_;
|
||||
uint32_t gamma_ramp_upload_memory_type_;
|
||||
// Mapping of either gamma_ramp_buffer_memory_ (if it's host-visible) or
|
||||
// gamma_ramp_upload_buffer_memory_ (otherwise).
|
||||
void* gamma_ramp_upload_mapping_;
|
||||
std::array<VkBufferView, 2 * kMaxFramesInFlight> gamma_ramp_buffer_views_{};
|
||||
// UINT32_MAX if outdated.
|
||||
uint32_t gamma_ramp_256_entry_table_current_frame_ = UINT32_MAX;
|
||||
uint32_t gamma_ramp_pwl_current_frame_ = UINT32_MAX;
|
||||
|
||||
VkDescriptorSetLayout swap_descriptor_set_layout_sampled_image_ =
|
||||
VK_NULL_HANDLE;
|
||||
VkDescriptorSetLayout swap_descriptor_set_layout_uniform_texel_buffer_ =
|
||||
VK_NULL_HANDLE;
|
||||
|
||||
// Descriptor pool for allocating descriptors needed for presentation, such as
|
||||
// the destination images and the gamma ramps.
|
||||
VkDescriptorPool swap_descriptor_pool_ = VK_NULL_HANDLE;
|
||||
// Interleaved 256-entry table and PWL texel buffer descriptors.
|
||||
// kMaxFramesInFlight pairs of gamma ramps if in host-visible memory and
|
||||
// uploaded directly, one otherwise.
|
||||
std::array<VkDescriptorSet, 2 * kMaxFramesInFlight>
|
||||
swap_descriptors_gamma_ramp_;
|
||||
// Sampled images.
|
||||
std::array<VkDescriptorSet, kMaxFramesInFlight> swap_descriptors_source_;
|
||||
|
||||
VkPipelineLayout swap_apply_gamma_pipeline_layout_ = VK_NULL_HANDLE;
|
||||
// Has no dependencies on specific pipeline stages on both ends to simplify
|
||||
// use in different scenarios with different pipelines - use explicit barriers
|
||||
// for synchronization. Drawing to VK_FORMAT_R8G8B8A8_SRGB.
|
||||
VkRenderPass swap_render_pass_ = VK_NULL_HANDLE;
|
||||
VkPipelineLayout swap_pipeline_layout_ = VK_NULL_HANDLE;
|
||||
VkPipeline swap_pipeline_ = VK_NULL_HANDLE;
|
||||
// for synchronization.
|
||||
VkRenderPass swap_apply_gamma_render_pass_ = VK_NULL_HANDLE;
|
||||
VkPipeline swap_apply_gamma_256_entry_table_pipeline_ = VK_NULL_HANDLE;
|
||||
VkPipeline swap_apply_gamma_pwl_pipeline_ = VK_NULL_HANDLE;
|
||||
|
||||
// Framebuffer for the current presenter's guest output image revision, and
|
||||
// its usage tracking.
|
||||
struct SwapFramebuffer {
|
||||
VkFramebuffer framebuffer = VK_NULL_HANDLE;
|
||||
uint64_t version = UINT64_MAX;
|
||||
uint64_t last_submission = 0;
|
||||
};
|
||||
std::array<SwapFramebuffer,
|
||||
ui::vulkan::VulkanPresenter::kMaxActiveGuestOutputImageVersions>
|
||||
swap_framebuffers_;
|
||||
std::deque<std::pair<uint64_t, VkFramebuffer>> swap_framebuffers_outdated_;
|
||||
|
||||
// Pending pipeline barriers.
|
||||
std::vector<VkBufferMemoryBarrier> pending_barriers_buffer_memory_barriers_;
|
||||
|
||||
@@ -589,6 +589,59 @@ VkImageView VulkanTextureCache::GetActiveBindingOrNullImageView(
|
||||
}
|
||||
}
|
||||
|
||||
VkImageView VulkanTextureCache::RequestSwapTexture(
|
||||
uint32_t& width_scaled_out, uint32_t& height_scaled_out,
|
||||
xenos::TextureFormat& format_out) {
|
||||
const auto& regs = register_file();
|
||||
const auto& fetch = regs.Get<xenos::xe_gpu_texture_fetch_t>(
|
||||
XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0);
|
||||
TextureKey key;
|
||||
BindingInfoFromFetchConstant(fetch, key, nullptr);
|
||||
if (!key.is_valid || key.base_page == 0 ||
|
||||
key.dimension != xenos::DataDimension::k2DOrStacked) {
|
||||
return nullptr;
|
||||
}
|
||||
VulkanTexture* texture =
|
||||
static_cast<VulkanTexture*>(FindOrCreateTexture(key));
|
||||
if (!texture) {
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
VkImageView texture_view = texture->GetView(
|
||||
false, GuestToHostSwizzle(fetch.swizzle, GetHostFormatSwizzle(key)),
|
||||
false);
|
||||
if (texture_view == VK_NULL_HANDLE) {
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
if (!LoadTextureData(*texture)) {
|
||||
return VK_NULL_HANDLE;
|
||||
}
|
||||
texture->MarkAsUsed();
|
||||
VulkanTexture::Usage old_usage =
|
||||
texture->SetUsage(VulkanTexture::Usage::kSwapSampled);
|
||||
if (old_usage != VulkanTexture::Usage::kSwapSampled) {
|
||||
VkPipelineStageFlags src_stage_mask, dst_stage_mask;
|
||||
VkAccessFlags src_access_mask, dst_access_mask;
|
||||
VkImageLayout old_layout, new_layout;
|
||||
GetTextureUsageMasks(old_usage, src_stage_mask, src_access_mask,
|
||||
old_layout);
|
||||
GetTextureUsageMasks(VulkanTexture::Usage::kSwapSampled, dst_stage_mask,
|
||||
dst_access_mask, new_layout);
|
||||
command_processor_.PushImageMemoryBarrier(
|
||||
texture->image(), ui::vulkan::util::InitializeSubresourceRange(),
|
||||
src_stage_mask, dst_stage_mask, src_access_mask, dst_access_mask,
|
||||
old_layout, new_layout);
|
||||
}
|
||||
// Only texture->key, not the result of BindingInfoFromFetchConstant, contains
|
||||
// whether the texture is scaled.
|
||||
key = texture->key();
|
||||
width_scaled_out =
|
||||
key.GetWidth() * (key.scaled_resolve ? draw_resolution_scale_x() : 1);
|
||||
height_scaled_out =
|
||||
key.GetHeight() * (key.scaled_resolve ? draw_resolution_scale_y() : 1);
|
||||
format_out = key.format;
|
||||
return texture_view;
|
||||
}
|
||||
|
||||
bool VulkanTextureCache::IsSignedVersionSeparateForFormat(
|
||||
TextureKey key) const {
|
||||
const HostFormatPair& host_format_pair = GetHostFormatPair(key);
|
||||
@@ -1263,7 +1316,14 @@ VulkanTextureCache::VulkanTexture::~VulkanTexture() {
|
||||
}
|
||||
|
||||
VkImageView VulkanTextureCache::VulkanTexture::GetView(bool is_signed,
|
||||
uint32_t host_swizzle) {
|
||||
uint32_t host_swizzle,
|
||||
bool is_array) {
|
||||
xenos::DataDimension dimension = key().dimension;
|
||||
if (dimension == xenos::DataDimension::k3D ||
|
||||
dimension == xenos::DataDimension::kCube) {
|
||||
is_array = false;
|
||||
}
|
||||
|
||||
const VulkanTextureCache& vulkan_texture_cache =
|
||||
static_cast<const VulkanTextureCache&>(texture_cache());
|
||||
|
||||
@@ -1297,6 +1357,8 @@ VkImageView VulkanTextureCache::VulkanTexture::GetView(bool is_signed,
|
||||
}
|
||||
view_key.host_swizzle = host_swizzle;
|
||||
|
||||
view_key.is_array = uint32_t(is_array);
|
||||
|
||||
// Try to find an existing view.
|
||||
auto it = views_.find(view_key);
|
||||
if (it != views_.end()) {
|
||||
@@ -1311,17 +1373,6 @@ VkImageView VulkanTextureCache::VulkanTexture::GetView(bool is_signed,
|
||||
view_create_info.pNext = nullptr;
|
||||
view_create_info.flags = 0;
|
||||
view_create_info.image = image();
|
||||
switch (key().dimension) {
|
||||
case xenos::DataDimension::k3D:
|
||||
view_create_info.viewType = VK_IMAGE_VIEW_TYPE_3D;
|
||||
break;
|
||||
case xenos::DataDimension::kCube:
|
||||
view_create_info.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
|
||||
break;
|
||||
default:
|
||||
view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
break;
|
||||
}
|
||||
view_create_info.format = format;
|
||||
view_create_info.components.r = GetComponentSwizzle(host_swizzle, 0);
|
||||
view_create_info.components.g = GetComponentSwizzle(host_swizzle, 1);
|
||||
@@ -1329,6 +1380,22 @@ VkImageView VulkanTextureCache::VulkanTexture::GetView(bool is_signed,
|
||||
view_create_info.components.a = GetComponentSwizzle(host_swizzle, 3);
|
||||
view_create_info.subresourceRange =
|
||||
ui::vulkan::util::InitializeSubresourceRange();
|
||||
switch (dimension) {
|
||||
case xenos::DataDimension::k3D:
|
||||
view_create_info.viewType = VK_IMAGE_VIEW_TYPE_3D;
|
||||
break;
|
||||
case xenos::DataDimension::kCube:
|
||||
view_create_info.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
|
||||
break;
|
||||
default:
|
||||
if (is_array) {
|
||||
view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
} else {
|
||||
view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
view_create_info.subresourceRange.layerCount = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
VkImageView view;
|
||||
if (dfn.vkCreateImageView(device, &view_create_info, nullptr, &view) !=
|
||||
VK_SUCCESS) {
|
||||
@@ -2248,9 +2315,10 @@ void VulkanTextureCache::GetTextureUsageMasks(VulkanTexture::Usage usage,
|
||||
layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
break;
|
||||
case VulkanTexture::Usage::kSwapSampled:
|
||||
// The swap texture is likely to be used only for the presentation compute
|
||||
// shader, and not during emulation, where it'd be used in other stages.
|
||||
stage_mask = VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT;
|
||||
// The swap texture is likely to be used only for the presentation
|
||||
// fragment shader, and not during emulation, where it'd be used in other
|
||||
// stages.
|
||||
stage_mask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
access_mask = VK_ACCESS_SHADER_READ_BIT;
|
||||
layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
break;
|
||||
|
||||
@@ -60,6 +60,13 @@ class VulkanTextureCache final : public TextureCache {
|
||||
xenos::FetchOpDimension dimension,
|
||||
bool is_signed) const;
|
||||
|
||||
// Returns the 2D view of the front buffer texture (for fragment shader
|
||||
// reading - the barrier will be pushed in the command processor if needed),
|
||||
// or VK_NULL_HANDLE in case of failure. May call LoadTextureData.
|
||||
VkImageView RequestSwapTexture(uint32_t& width_scaled_out,
|
||||
uint32_t& height_scaled_out,
|
||||
xenos::TextureFormat& format_out);
|
||||
|
||||
protected:
|
||||
bool IsSignedVersionSeparateForFormat(TextureKey key) const override;
|
||||
uint32_t GetHostFormatSwizzle(TextureKey key) const override;
|
||||
@@ -136,7 +143,8 @@ class VulkanTextureCache final : public TextureCache {
|
||||
return old_usage;
|
||||
}
|
||||
|
||||
VkImageView GetView(bool is_signed, uint32_t host_swizzle);
|
||||
VkImageView GetView(bool is_signed, uint32_t host_swizzle,
|
||||
bool is_array = true);
|
||||
|
||||
private:
|
||||
union ViewKey {
|
||||
@@ -144,6 +152,7 @@ class VulkanTextureCache final : public TextureCache {
|
||||
struct {
|
||||
uint32_t is_signed_separate_view : 1;
|
||||
uint32_t host_swizzle : 12;
|
||||
uint32_t is_array : 1;
|
||||
};
|
||||
|
||||
ViewKey() : key(0) { static_assert_size(*this, sizeof(key)); }
|
||||
|
||||
Reference in New Issue
Block a user