[Vulkan] Texture object and view creation
This commit is contained in:
parent
b0e1916f75
commit
08769de68b
|
@ -738,6 +738,10 @@ void VulkanCommandProcessor::WriteRegister(uint32_t index, uint32_t value) {
|
|||
index <= XE_GPU_REG_SHADER_CONSTANT_FETCH_31_5) {
|
||||
current_graphics_descriptor_set_values_up_to_date_ &=
|
||||
~(UINT32_C(1) << SpirvShaderTranslator::kDescriptorSetFetchConstants);
|
||||
if (texture_cache_) {
|
||||
texture_cache_->TextureFetchConstantWritten(
|
||||
(index - XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0) / 6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1548,13 +1552,6 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
|
|||
*pixel_shader, normalized_color_mask)
|
||||
: SpirvShaderTranslator::Modification(0);
|
||||
|
||||
// Set up the render targets - this may perform dispatches and draws.
|
||||
if (!render_target_cache_->Update(is_rasterization_done,
|
||||
normalized_depth_control,
|
||||
normalized_color_mask, *vertex_shader)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Translate the shaders.
|
||||
VulkanShader::VulkanTranslation* vertex_shader_translation =
|
||||
static_cast<VulkanShader::VulkanTranslation*>(
|
||||
|
@ -1566,6 +1563,23 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
|
|||
pixel_shader_modification.value))
|
||||
: nullptr;
|
||||
|
||||
// Update the textures before other work in the submission because samplers
|
||||
// depend on this (and in case of sampler overflow in a submission,
|
||||
// submissions must be split) - may perform dispatches.
|
||||
uint32_t used_texture_mask =
|
||||
vertex_shader->GetUsedTextureMaskAfterTranslation() |
|
||||
(pixel_shader != nullptr
|
||||
? pixel_shader->GetUsedTextureMaskAfterTranslation()
|
||||
: 0);
|
||||
texture_cache_->RequestTextures(used_texture_mask);
|
||||
|
||||
// Set up the render targets - this may perform dispatches and draws.
|
||||
if (!render_target_cache_->Update(is_rasterization_done,
|
||||
normalized_depth_control,
|
||||
normalized_color_mask, *vertex_shader)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update the graphics pipeline, and if the new graphics pipeline has a
|
||||
// different layout, invalidate incompatible descriptor sets before updating
|
||||
// current_guest_graphics_pipeline_layout_.
|
||||
|
@ -2758,7 +2772,9 @@ bool VulkanCommandProcessor::UpdateBindings(const VulkanShader* vertex_shader,
|
|||
VkDescriptorImageInfo& descriptor_image_info =
|
||||
descriptor_write_image_info_.emplace_back();
|
||||
descriptor_image_info.imageView =
|
||||
texture_cache_->GetNullImageView(texture_binding.dimension);
|
||||
texture_cache_->GetActiveBindingOrNullImageView(
|
||||
texture_binding.fetch_constant, texture_binding.dimension,
|
||||
bool(texture_binding.is_signed));
|
||||
descriptor_image_info.imageLayout =
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
}
|
||||
|
@ -2782,7 +2798,9 @@ bool VulkanCommandProcessor::UpdateBindings(const VulkanShader* vertex_shader,
|
|||
VkDescriptorImageInfo& descriptor_image_info =
|
||||
descriptor_write_image_info_.emplace_back();
|
||||
descriptor_image_info.imageView =
|
||||
texture_cache_->GetNullImageView(texture_binding.dimension);
|
||||
texture_cache_->GetActiveBindingOrNullImageView(
|
||||
texture_binding.fetch_constant, texture_binding.dimension,
|
||||
bool(texture_binding.is_signed));
|
||||
descriptor_image_info.imageLayout =
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -12,8 +12,10 @@
|
|||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include "xenia/base/hash.h"
|
||||
#include "xenia/gpu/texture_cache.h"
|
||||
#include "xenia/gpu/vulkan/vulkan_shared_memory.h"
|
||||
#include "xenia/ui/vulkan/vulkan_provider.h"
|
||||
|
@ -45,18 +47,19 @@ class VulkanTextureCache final : public TextureCache {
|
|||
|
||||
void BeginSubmission(uint64_t new_submission_index) override;
|
||||
|
||||
VkImageView GetNullImageView(xenos::FetchOpDimension dimension) const {
|
||||
switch (dimension) {
|
||||
case xenos::FetchOpDimension::k3DOrStacked:
|
||||
return null_image_view_3d_;
|
||||
case xenos::FetchOpDimension::kCube:
|
||||
return null_image_view_cube_;
|
||||
default:
|
||||
return null_image_view_2d_array_;
|
||||
}
|
||||
}
|
||||
// Must be called within a frame - creates and untiles textures needed by
|
||||
// shaders, and enqueues transitioning them into the sampled usage. This may
|
||||
// bind compute pipelines (notifying the command processor about that), and
|
||||
// also since it may insert deferred barriers, before flushing the barriers
|
||||
// preceding host GPU work.
|
||||
void RequestTextures(uint32_t used_texture_mask) override;
|
||||
|
||||
VkImageView GetActiveBindingOrNullImageView(uint32_t fetch_constant_index,
|
||||
xenos::FetchOpDimension dimension,
|
||||
bool is_signed) const;
|
||||
|
||||
protected:
|
||||
bool IsSignedVersionSeparateForFormat(TextureKey key) const override;
|
||||
uint32_t GetHostFormatSwizzle(TextureKey key) const override;
|
||||
|
||||
uint32_t GetMaxHostTextureWidthHeight(
|
||||
|
@ -69,13 +72,187 @@ class VulkanTextureCache final : public TextureCache {
|
|||
bool LoadTextureDataFromResidentMemoryImpl(Texture& texture, bool load_base,
|
||||
bool load_mips) override;
|
||||
|
||||
void UpdateTextureBindingsImpl(uint32_t fetch_constant_mask) override;
|
||||
|
||||
private:
|
||||
enum class LoadMode {
|
||||
k8bpb,
|
||||
k16bpb,
|
||||
k32bpb,
|
||||
k64bpb,
|
||||
k128bpb,
|
||||
kR5G5B5A1ToB5G5R5A1,
|
||||
kR5G6B5ToB5G6R5,
|
||||
kR5G5B6ToB5G6R5WithRBGASwizzle,
|
||||
kRGBA4ToARGB4,
|
||||
kR10G11B11ToRGBA16,
|
||||
kR10G11B11ToRGBA16SNorm,
|
||||
kR11G11B10ToRGBA16,
|
||||
kR11G11B10ToRGBA16SNorm,
|
||||
kR16UNormToFloat,
|
||||
kR16SNormToFloat,
|
||||
kRG16UNormToFloat,
|
||||
kRG16SNormToFloat,
|
||||
kRGBA16UNormToFloat,
|
||||
kRGBA16SNormToFloat,
|
||||
kDXT1ToRGBA8,
|
||||
kDXT3ToRGBA8,
|
||||
kDXT5ToRGBA8,
|
||||
kDXNToRG8,
|
||||
kDXT3A,
|
||||
kDXT3AAs1111ToARGB4,
|
||||
kDXT5AToR8,
|
||||
kCTX1,
|
||||
kDepthUnorm,
|
||||
kDepthFloat,
|
||||
|
||||
kCount,
|
||||
|
||||
kUnknown = kCount
|
||||
};
|
||||
|
||||
struct HostFormat {
|
||||
LoadMode load_mode;
|
||||
// Do NOT add integer formats to this - they are not filterable, can only be
|
||||
// read with ImageFetch, not ImageSample! If any game is seen using
|
||||
// num_format 1 for fixed-point formats (for floating-point, it's normally
|
||||
// set to 1 though), add a constant buffer containing multipliers for the
|
||||
// textures and multiplication to the tfetch implementation.
|
||||
VkFormat format;
|
||||
uint32_t block_width_log2;
|
||||
uint32_t block_height_log2;
|
||||
|
||||
// Set up dynamically based on what's supported by the device.
|
||||
bool linear_filterable;
|
||||
};
|
||||
|
||||
struct HostFormatPair {
|
||||
HostFormat format_unsigned;
|
||||
HostFormat format_signed;
|
||||
// Mapping of Xenos swizzle components to Vulkan format components.
|
||||
uint32_t swizzle;
|
||||
// Whether the unsigned and the signed formats are compatible for one image
|
||||
// and the same image data (on a portability subset device, this should also
|
||||
// take imageViewFormatReinterpretation into account).
|
||||
bool unsigned_signed_compatible;
|
||||
};
|
||||
|
||||
class VulkanTexture final : public Texture {
|
||||
public:
|
||||
enum class Usage {
|
||||
kUndefined,
|
||||
kTransferDestination,
|
||||
kGuestShaderSampled,
|
||||
kSwapSampled,
|
||||
};
|
||||
|
||||
// Takes ownership of the image and its memory.
|
||||
explicit VulkanTexture(VulkanTextureCache& texture_cache,
|
||||
const TextureKey& key);
|
||||
const TextureKey& key, VkImage image,
|
||||
VkDeviceMemory memory, VkDeviceSize memory_size);
|
||||
~VulkanTexture();
|
||||
|
||||
VkImage image() const { return image_; }
|
||||
|
||||
// Doesn't transition (the caller must insert the barrier).
|
||||
Usage SetUsage(Usage new_usage) {
|
||||
Usage old_usage = usage_;
|
||||
usage_ = new_usage;
|
||||
return old_usage;
|
||||
}
|
||||
|
||||
VkImageView GetView(bool is_signed, uint32_t host_swizzle);
|
||||
|
||||
private:
|
||||
union ViewKey {
|
||||
uint32_t key;
|
||||
struct {
|
||||
uint32_t is_signed_separate_view : 1;
|
||||
uint32_t host_swizzle : 12;
|
||||
};
|
||||
|
||||
ViewKey() : key(0) { static_assert_size(*this, sizeof(key)); }
|
||||
|
||||
struct Hasher {
|
||||
size_t operator()(const ViewKey& key) const {
|
||||
return std::hash<decltype(key.key)>{}(key.key);
|
||||
}
|
||||
};
|
||||
bool operator==(const ViewKey& other_key) const {
|
||||
return key == other_key.key;
|
||||
}
|
||||
bool operator!=(const ViewKey& other_key) const {
|
||||
return !(*this == other_key);
|
||||
}
|
||||
};
|
||||
|
||||
static constexpr VkComponentSwizzle GetComponentSwizzle(
|
||||
uint32_t texture_swizzle, uint32_t component_index) {
|
||||
xenos::XE_GPU_TEXTURE_SWIZZLE texture_component_swizzle =
|
||||
xenos::XE_GPU_TEXTURE_SWIZZLE(
|
||||
(texture_swizzle >> (3 * component_index)) & 0b111);
|
||||
if (texture_component_swizzle ==
|
||||
xenos::XE_GPU_TEXTURE_SWIZZLE(component_index)) {
|
||||
// The portability subset requires all swizzles to be IDENTITY, return
|
||||
// IDENTITY specifically, not R, G, B, A.
|
||||
return VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
}
|
||||
switch (texture_component_swizzle) {
|
||||
case xenos::XE_GPU_TEXTURE_SWIZZLE_R:
|
||||
return VK_COMPONENT_SWIZZLE_R;
|
||||
case xenos::XE_GPU_TEXTURE_SWIZZLE_G:
|
||||
return VK_COMPONENT_SWIZZLE_G;
|
||||
case xenos::XE_GPU_TEXTURE_SWIZZLE_B:
|
||||
return VK_COMPONENT_SWIZZLE_B;
|
||||
case xenos::XE_GPU_TEXTURE_SWIZZLE_A:
|
||||
return VK_COMPONENT_SWIZZLE_A;
|
||||
case xenos::XE_GPU_TEXTURE_SWIZZLE_0:
|
||||
return VK_COMPONENT_SWIZZLE_ZERO;
|
||||
case xenos::XE_GPU_TEXTURE_SWIZZLE_1:
|
||||
return VK_COMPONENT_SWIZZLE_ONE;
|
||||
default:
|
||||
// An invalid value.
|
||||
return VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
}
|
||||
}
|
||||
|
||||
VkImage image_;
|
||||
VkDeviceMemory memory_;
|
||||
|
||||
Usage usage_ = Usage::kUndefined;
|
||||
|
||||
std::unordered_map<ViewKey, VkImageView, ViewKey::Hasher> views_;
|
||||
};
|
||||
|
||||
struct VulkanTextureBinding {
|
||||
VkImageView image_view_unsigned;
|
||||
VkImageView image_view_signed;
|
||||
|
||||
VulkanTextureBinding() { Reset(); }
|
||||
|
||||
void Reset() {
|
||||
image_view_unsigned = VK_NULL_HANDLE;
|
||||
image_view_signed = VK_NULL_HANDLE;
|
||||
}
|
||||
};
|
||||
|
||||
static constexpr bool AreDimensionsCompatible(
|
||||
xenos::FetchOpDimension binding_dimension,
|
||||
xenos::DataDimension resource_dimension) {
|
||||
switch (binding_dimension) {
|
||||
case xenos::FetchOpDimension::k1D:
|
||||
case xenos::FetchOpDimension::k2D:
|
||||
return resource_dimension == xenos::DataDimension::k1D ||
|
||||
resource_dimension == xenos::DataDimension::k2DOrStacked;
|
||||
case xenos::FetchOpDimension::k3DOrStacked:
|
||||
return resource_dimension == xenos::DataDimension::k3D;
|
||||
case xenos::FetchOpDimension::kCube:
|
||||
return resource_dimension == xenos::DataDimension::kCube;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
explicit VulkanTextureCache(
|
||||
const RegisterFile& register_file, VulkanSharedMemory& shared_memory,
|
||||
uint32_t draw_resolution_scale_x, uint32_t draw_resolution_scale_y,
|
||||
|
@ -84,9 +261,16 @@ class VulkanTextureCache final : public TextureCache {
|
|||
|
||||
bool Initialize();
|
||||
|
||||
void GetTextureUsageMasks(VulkanTexture::Usage usage,
|
||||
VkPipelineStageFlags& stage_mask,
|
||||
VkAccessFlags& access_mask, VkImageLayout& layout);
|
||||
|
||||
VulkanCommandProcessor& command_processor_;
|
||||
VkPipelineStageFlags guest_shader_pipeline_stages_;
|
||||
|
||||
static const HostFormatPair kBestHostFormats[64];
|
||||
HostFormatPair host_formats_[64];
|
||||
|
||||
// If both images can be placed in the same allocation, it's one allocation,
|
||||
// otherwise it's two separate.
|
||||
std::array<VkDeviceMemory, 2> null_images_memory_{};
|
||||
|
@ -96,6 +280,9 @@ class VulkanTextureCache final : public TextureCache {
|
|||
VkImageView null_image_view_cube_ = VK_NULL_HANDLE;
|
||||
VkImageView null_image_view_3d_ = VK_NULL_HANDLE;
|
||||
bool null_images_cleared_ = false;
|
||||
|
||||
std::array<VulkanTextureBinding, xenos::kTextureFetchConstantCount>
|
||||
vulkan_texture_bindings_;
|
||||
};
|
||||
|
||||
} // namespace vulkan
|
||||
|
|
|
@ -5,6 +5,7 @@ XE_UI_VULKAN_FUNCTION(vkEnumerateDeviceExtensionProperties)
|
|||
XE_UI_VULKAN_FUNCTION(vkEnumeratePhysicalDevices)
|
||||
XE_UI_VULKAN_FUNCTION(vkGetDeviceProcAddr)
|
||||
XE_UI_VULKAN_FUNCTION(vkGetPhysicalDeviceFeatures)
|
||||
XE_UI_VULKAN_FUNCTION(vkGetPhysicalDeviceFormatProperties)
|
||||
XE_UI_VULKAN_FUNCTION(vkGetPhysicalDeviceMemoryProperties)
|
||||
XE_UI_VULKAN_FUNCTION(vkGetPhysicalDeviceProperties)
|
||||
XE_UI_VULKAN_FUNCTION(vkGetPhysicalDeviceQueueFamilyProperties)
|
||||
|
|
Loading…
Reference in New Issue