vk_rasterizer: Small cleanup
This commit is contained in:
@@ -450,12 +450,21 @@ void RasterizerVulkan::DrawTriangles() {
|
||||
return;
|
||||
}
|
||||
|
||||
const u64 vertex_size = vertex_batch.size() * sizeof(HardwareVertex);
|
||||
pipeline_info.rasterization.topology.Assign(Pica::PipelineRegs::TriangleTopology::List);
|
||||
pipeline_info.vertex_layout = software_layout;
|
||||
|
||||
pipeline_cache.UseTrivialVertexShader();
|
||||
pipeline_cache.UseTrivialGeometryShader();
|
||||
|
||||
auto [buffer, offset, _] = stream_buffer.Map(vertex_size, sizeof(HardwareVertex));
|
||||
std::memcpy(buffer, vertex_batch.data(), vertex_size);
|
||||
stream_buffer.Commit(vertex_size);
|
||||
|
||||
scheduler.Record([this, offset = offset](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.bindVertexBuffers(0, stream_buffer.Handle(), offset);
|
||||
});
|
||||
|
||||
Draw(false, false);
|
||||
}
|
||||
|
||||
@@ -537,45 +546,79 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
|
||||
uniform_block_data.dirty = true;
|
||||
}
|
||||
|
||||
const auto BindCubeFace = [&](Pica::TexturingRegs::CubeFace face,
|
||||
Pica::Texture::TextureInfo& info) {
|
||||
info.physical_address = regs.texturing.GetCubePhysicalAddress(face);
|
||||
auto surface = res_cache.GetTextureSurface(info);
|
||||
|
||||
const u32 binding = static_cast<u32>(face);
|
||||
if (surface) {
|
||||
pipeline_cache.BindStorageImage(binding, surface->ImageView());
|
||||
} else {
|
||||
pipeline_cache.BindStorageImage(binding, null_storage_surface.ImageView());
|
||||
}
|
||||
};
|
||||
|
||||
const auto BindSampler = [&](u32 binding, SamplerInfo& info,
|
||||
const Pica::TexturingRegs::TextureConfig& config) {
|
||||
// TODO(GPUCode): Cubemaps don't contain any mipmaps for now, so sampling from them returns
|
||||
// nothing. Always sample from the base level until mipmaps for texture cubes are
|
||||
// implemented
|
||||
const bool skip_mipmap = config.type == Pica::TexturingRegs::TextureConfig::TextureCube;
|
||||
info = SamplerInfo{.mag_filter = config.mag_filter,
|
||||
.min_filter = config.min_filter,
|
||||
.mip_filter = config.mip_filter,
|
||||
.wrap_s = config.wrap_s,
|
||||
.wrap_t = config.wrap_t,
|
||||
.border_color = config.border_color.raw,
|
||||
.lod_min = skip_mipmap ? 0.f : static_cast<float>(config.lod.min_level),
|
||||
.lod_max = skip_mipmap ? 0.f : static_cast<float>(config.lod.max_level)};
|
||||
|
||||
// Search the cache and bind the appropriate sampler
|
||||
if (auto it = samplers.find(info); it != samplers.end()) {
|
||||
pipeline_cache.BindSampler(binding, it->second);
|
||||
} else {
|
||||
vk::Sampler texture_sampler = CreateSampler(info);
|
||||
samplers.emplace(info, texture_sampler);
|
||||
pipeline_cache.BindSampler(binding, texture_sampler);
|
||||
}
|
||||
};
|
||||
|
||||
// Sync and bind the texture surfaces
|
||||
// NOTE: From here onwards its a safe zone to set the draw state, doing that any earlier will
|
||||
// cause issues as the rasterizer cache might cause a scheduler switch and invalidate our state
|
||||
SyncTextureUnits(color_surface.get());
|
||||
|
||||
const vk::Rect2D render_area = {
|
||||
.offset{static_cast<s32>(draw_rect.left), static_cast<s32>(draw_rect.bottom)},
|
||||
.extent{draw_rect.GetWidth(), draw_rect.GetHeight()},
|
||||
};
|
||||
renderpass_cache.EnterRenderpass(color_surface.get(), depth_surface.get(), render_area);
|
||||
|
||||
// Sync and bind the shader
|
||||
if (shader_dirty) {
|
||||
pipeline_cache.UseFragmentShader(regs);
|
||||
shader_dirty = false;
|
||||
}
|
||||
|
||||
// Sync the LUTs within the texture buffer
|
||||
SyncAndUploadLUTs();
|
||||
SyncAndUploadLUTsLF();
|
||||
|
||||
// Sync the uniform data
|
||||
UploadUniforms(accelerate);
|
||||
|
||||
// Sync the viewport
|
||||
pipeline_cache.SetViewport(surfaces_rect.left + viewport_rect_unscaled.left * res_scale,
|
||||
surfaces_rect.bottom + viewport_rect_unscaled.bottom * res_scale,
|
||||
viewport_rect_unscaled.GetWidth() * res_scale,
|
||||
viewport_rect_unscaled.GetHeight() * res_scale);
|
||||
|
||||
// Viewport can have negative offsets or larger dimensions than our framebuffer sub-rect.
|
||||
// Enable scissor test to prevent drawing outside of the framebuffer region
|
||||
pipeline_cache.SetScissor(draw_rect.left, draw_rect.bottom, draw_rect.GetWidth(),
|
||||
draw_rect.GetHeight());
|
||||
|
||||
// Draw the vertex batch
|
||||
bool succeeded = true;
|
||||
if (accelerate) {
|
||||
succeeded = AccelerateDrawBatchInternal(is_indexed);
|
||||
} else {
|
||||
pipeline_cache.BindPipeline(pipeline_info, true);
|
||||
scheduler.Record([vertex_count = vertex_batch.size()](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.draw(vertex_count, 1, 0, 0);
|
||||
});
|
||||
}
|
||||
|
||||
vertex_batch.clear();
|
||||
|
||||
// Mark framebuffer surfaces as dirty
|
||||
const Common::Rectangle draw_rect_unscaled{draw_rect / res_scale};
|
||||
if (color_surface && write_color_fb) {
|
||||
auto interval = color_surface->GetSubRectInterval(draw_rect_unscaled);
|
||||
res_cache.InvalidateRegion(boost::icl::first(interval), boost::icl::length(interval),
|
||||
color_surface);
|
||||
}
|
||||
|
||||
if (depth_surface && write_depth_fb) {
|
||||
auto interval = depth_surface->GetSubRectInterval(draw_rect_unscaled);
|
||||
res_cache.InvalidateRegion(boost::icl::first(interval), boost::icl::length(interval),
|
||||
depth_surface);
|
||||
}
|
||||
|
||||
static int counter = 20;
|
||||
counter--;
|
||||
if (counter == 0) {
|
||||
scheduler.DispatchWork();
|
||||
counter = 20;
|
||||
}
|
||||
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
void RasterizerVulkan::SyncTextureUnits(Surface* const color_surface) {
|
||||
const auto pica_textures = regs.texturing.GetTextures();
|
||||
for (u32 texture_index = 0; texture_index < pica_textures.size(); ++texture_index) {
|
||||
const auto& texture = pica_textures[texture_index];
|
||||
@@ -597,12 +640,20 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
|
||||
using CubeFace = Pica::TexturingRegs::CubeFace;
|
||||
auto info = Pica::Texture::TextureInfo::FromPicaRegister(texture.config,
|
||||
texture.format);
|
||||
BindCubeFace(CubeFace::PositiveX, info);
|
||||
BindCubeFace(CubeFace::NegativeX, info);
|
||||
BindCubeFace(CubeFace::PositiveY, info);
|
||||
BindCubeFace(CubeFace::NegativeY, info);
|
||||
BindCubeFace(CubeFace::PositiveZ, info);
|
||||
BindCubeFace(CubeFace::NegativeZ, info);
|
||||
for (CubeFace face :
|
||||
{CubeFace::PositiveX, CubeFace::NegativeX, CubeFace::PositiveY,
|
||||
CubeFace::NegativeY, CubeFace::PositiveZ, CubeFace::NegativeZ}) {
|
||||
info.physical_address = regs.texturing.GetCubePhysicalAddress(face);
|
||||
auto surface = res_cache.GetTextureSurface(info);
|
||||
|
||||
const u32 binding = static_cast<u32>(face);
|
||||
if (surface) {
|
||||
pipeline_cache.BindStorageImage(binding, surface->ImageView());
|
||||
} else {
|
||||
pipeline_cache.BindStorageImage(binding,
|
||||
null_storage_surface.ImageView());
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
case TextureType::TextureCube: {
|
||||
@@ -669,96 +720,6 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
|
||||
pipeline_cache.BindSampler(texture_index, default_sampler);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: From here onwards its a safe zone to set the draw state, doing that any earlier will
|
||||
// cause issues as the rasterizer cache might cause a scheduler switch and invalidate our state
|
||||
const vk::Rect2D render_area = {
|
||||
.offset{
|
||||
.x = static_cast<s32>(draw_rect.left),
|
||||
.y = static_cast<s32>(draw_rect.bottom),
|
||||
},
|
||||
.extent{
|
||||
.width = draw_rect.GetWidth(),
|
||||
.height = draw_rect.GetHeight(),
|
||||
},
|
||||
};
|
||||
|
||||
renderpass_cache.EnterRenderpass(color_surface.get(), depth_surface.get(), render_area);
|
||||
|
||||
// Sync and bind the shader
|
||||
if (shader_dirty) {
|
||||
pipeline_cache.UseFragmentShader(regs);
|
||||
shader_dirty = false;
|
||||
}
|
||||
|
||||
// Sync the LUTs within the texture buffer
|
||||
SyncAndUploadLUTs();
|
||||
SyncAndUploadLUTsLF();
|
||||
|
||||
// Sync the uniform data
|
||||
UploadUniforms(accelerate);
|
||||
|
||||
// Sync the viewport
|
||||
pipeline_cache.SetViewport(surfaces_rect.left + viewport_rect_unscaled.left * res_scale,
|
||||
surfaces_rect.bottom + viewport_rect_unscaled.bottom * res_scale,
|
||||
viewport_rect_unscaled.GetWidth() * res_scale,
|
||||
viewport_rect_unscaled.GetHeight() * res_scale);
|
||||
|
||||
// Viewport can have negative offsets or larger dimensions than our framebuffer sub-rect.
|
||||
// Enable scissor test to prevent drawing outside of the framebuffer region
|
||||
pipeline_cache.SetScissor(draw_rect.left, draw_rect.bottom, draw_rect.GetWidth(),
|
||||
draw_rect.GetHeight());
|
||||
|
||||
// Draw the vertex batch
|
||||
bool succeeded = true;
|
||||
if (accelerate) {
|
||||
succeeded = AccelerateDrawBatchInternal(is_indexed);
|
||||
} else {
|
||||
pipeline_cache.BindPipeline(pipeline_info, true);
|
||||
|
||||
const u32 max_vertices = STREAM_BUFFER_SIZE / sizeof(HardwareVertex);
|
||||
const u32 batch_size = static_cast<u32>(vertex_batch.size());
|
||||
for (u32 base_vertex = 0; base_vertex < batch_size; base_vertex += max_vertices) {
|
||||
const u32 vertices = std::min(max_vertices, batch_size - base_vertex);
|
||||
const u32 vertex_size = vertices * sizeof(HardwareVertex);
|
||||
|
||||
// Copy vertex data
|
||||
auto [array_ptr, offset, _] = stream_buffer.Map(vertex_size, sizeof(HardwareVertex));
|
||||
std::memcpy(array_ptr, vertex_batch.data() + base_vertex, vertex_size);
|
||||
stream_buffer.Commit(vertex_size);
|
||||
|
||||
scheduler.Record(
|
||||
[this, vertices, base_vertex, offset = offset](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.bindVertexBuffers(0, stream_buffer.Handle(), offset);
|
||||
cmdbuf.draw(vertices, 1, base_vertex, 0);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
vertex_batch.clear();
|
||||
|
||||
// Mark framebuffer surfaces as dirty
|
||||
const Common::Rectangle draw_rect_unscaled{draw_rect / res_scale};
|
||||
if (color_surface && write_color_fb) {
|
||||
auto interval = color_surface->GetSubRectInterval(draw_rect_unscaled);
|
||||
res_cache.InvalidateRegion(boost::icl::first(interval), boost::icl::length(interval),
|
||||
color_surface);
|
||||
}
|
||||
|
||||
if (depth_surface && write_depth_fb) {
|
||||
auto interval = depth_surface->GetSubRectInterval(draw_rect_unscaled);
|
||||
res_cache.InvalidateRegion(boost::icl::first(interval), boost::icl::length(interval),
|
||||
depth_surface);
|
||||
}
|
||||
|
||||
static int counter = 20;
|
||||
counter--;
|
||||
if (counter == 0) {
|
||||
scheduler.DispatchWork();
|
||||
counter = 20;
|
||||
}
|
||||
|
||||
return succeeded;
|
||||
}
|
||||
|
||||
void RasterizerVulkan::NotifyFixedFunctionPicaRegisterChanged(u32 id) {
|
||||
@@ -1045,6 +1006,30 @@ void RasterizerVulkan::MakeSoftwareVertexLayout() {
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::BindSampler(u32 unit, SamplerInfo& info,
|
||||
const Pica::TexturingRegs::TextureConfig& config) {
|
||||
// TODO: Cubemaps don't contain any mipmaps for now, so sampling from them returns
|
||||
// nothing. Always sample from the base level until mipmaps for texture cubes are
|
||||
// implemented
|
||||
const bool skip_mipmap = config.type == Pica::TexturingRegs::TextureConfig::TextureCube;
|
||||
info = SamplerInfo{
|
||||
.mag_filter = config.mag_filter,
|
||||
.min_filter = config.min_filter,
|
||||
.mip_filter = config.mip_filter,
|
||||
.wrap_s = config.wrap_s,
|
||||
.wrap_t = config.wrap_t,
|
||||
.border_color = config.border_color.raw,
|
||||
.lod_min = skip_mipmap ? 0.f : static_cast<float>(config.lod.min_level),
|
||||
.lod_max = skip_mipmap ? 0.f : static_cast<float>(config.lod.max_level),
|
||||
};
|
||||
|
||||
auto [it, new_sampler] = samplers.try_emplace(info);
|
||||
if (new_sampler) {
|
||||
it->second = CreateSampler(info);
|
||||
}
|
||||
pipeline_cache.BindSampler(unit, it->second);
|
||||
}
|
||||
|
||||
vk::Sampler RasterizerVulkan::CreateSampler(const SamplerInfo& info) {
|
||||
const bool use_border_color = instance.IsCustomBorderColorSupported() &&
|
||||
(info.wrap_s == SamplerInfo::TextureConfig::ClampToBorder ||
|
||||
|
@@ -122,6 +122,9 @@ private:
|
||||
void SyncAndUploadLUTs();
|
||||
void SyncAndUploadLUTsLF();
|
||||
|
||||
/// Syncs all enabled PICA texture units
|
||||
void SyncTextureUnits(Surface* const color_surface);
|
||||
|
||||
/// Upload the uniform blocks to the uniform buffer object
|
||||
void UploadUniforms(bool accelerate_draw);
|
||||
|
||||
@@ -149,6 +152,9 @@ private:
|
||||
/// Creates the vertex layout struct used for software shader pipelines
|
||||
void MakeSoftwareVertexLayout();
|
||||
|
||||
/// Binds a sampler to the specified texture unit
|
||||
void BindSampler(u32 unit, SamplerInfo& info, const Pica::TexturingRegs::TextureConfig& config);
|
||||
|
||||
/// Creates a new sampler object
|
||||
vk::Sampler CreateSampler(const SamplerInfo& info);
|
||||
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#include "common/alignment.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/polyfill_thread.h"
|
||||
#include "video_core/renderer_vulkan/vk_master_semaphore.h"
|
||||
#include "video_core/renderer_vulkan/vk_resource_pool.h"
|
||||
@@ -98,6 +99,7 @@ public:
|
||||
void Wait(u64 tick) {
|
||||
if (tick >= master_semaphore.CurrentTick()) {
|
||||
// Make sure we are not waiting for the current tick without signalling
|
||||
LOG_WARNING(Render_Vulkan, "Flushing current tick");
|
||||
Flush();
|
||||
}
|
||||
master_semaphore.Wait(tick);
|
||||
|
@@ -19,6 +19,8 @@ MICROPROFILE_DEFINE(Vulkan_Download, "Vulkan", "Texture Download", MP_RGB(128, 1
|
||||
|
||||
namespace Vulkan {
|
||||
|
||||
using VideoCore::PixelFormatAsString;
|
||||
|
||||
struct RecordParams {
|
||||
vk::ImageAspectFlags aspect;
|
||||
vk::Filter filter;
|
||||
@@ -127,10 +129,10 @@ TextureRuntime::~TextureRuntime() {
|
||||
|
||||
for (const auto& [key, alloc] : texture_recycler) {
|
||||
vmaDestroyImage(allocator, alloc.image, alloc.allocation);
|
||||
device.destroyImageView(alloc.image_view);
|
||||
if (alloc.base_view) {
|
||||
if (alloc.base_view && alloc.base_view != alloc.image_view) {
|
||||
device.destroyImageView(alloc.base_view);
|
||||
}
|
||||
device.destroyImageView(alloc.image_view);
|
||||
if (alloc.depth_view) {
|
||||
device.destroyImageView(alloc.depth_view);
|
||||
device.destroyImageView(alloc.stencil_view);
|
||||
@@ -264,59 +266,8 @@ ImageAlloc TextureRuntime::Allocate(u32 width, u32 height, VideoCore::PixelForma
|
||||
|
||||
vk::Device device = instance.GetDevice();
|
||||
alloc.image_view = device.createImageView(view_info);
|
||||
|
||||
// Also create a base mip view in case this is used as an attachment
|
||||
if (levels > 1) [[likely]] {
|
||||
const vk::ImageViewCreateInfo base_view_info = {
|
||||
.image = alloc.image,
|
||||
.viewType = view_type,
|
||||
.format = format,
|
||||
.subresourceRange{
|
||||
.aspectMask = alloc.aspect,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = layers,
|
||||
},
|
||||
};
|
||||
|
||||
alloc.base_view = device.createImageView(base_view_info);
|
||||
}
|
||||
|
||||
// Create seperate depth/stencil views in case this gets reinterpreted with a compute shader
|
||||
if (alloc.aspect & vk::ImageAspectFlagBits::eStencil) {
|
||||
vk::ImageViewCreateInfo view_info = {
|
||||
.image = alloc.image,
|
||||
.viewType = view_type,
|
||||
.format = format,
|
||||
.subresourceRange{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eDepth,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = levels,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = layers,
|
||||
},
|
||||
};
|
||||
|
||||
alloc.depth_view = device.createImageView(view_info);
|
||||
view_info.subresourceRange.aspectMask = vk::ImageAspectFlagBits::eStencil;
|
||||
alloc.stencil_view = device.createImageView(view_info);
|
||||
}
|
||||
|
||||
if (create_storage_view) {
|
||||
const vk::ImageViewCreateInfo storage_view_info = {
|
||||
.image = alloc.image,
|
||||
.viewType = view_type,
|
||||
.format = vk::Format::eR32Uint,
|
||||
.subresourceRange{
|
||||
.aspectMask = alloc.aspect,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = levels,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = layers,
|
||||
},
|
||||
};
|
||||
alloc.storage_view = device.createImageView(storage_view_info);
|
||||
if (levels == 1) {
|
||||
alloc.base_view = alloc.image_view;
|
||||
}
|
||||
|
||||
renderpass_cache.ExitRenderpass();
|
||||
@@ -1051,6 +1002,100 @@ vk::PipelineStageFlags Surface::PipelineStageFlags() const noexcept {
|
||||
: vk::PipelineStageFlagBits::eNone);
|
||||
}
|
||||
|
||||
vk::ImageView Surface::FramebufferView() noexcept {
|
||||
vk::ImageView& base_view = alloc.base_view;
|
||||
if (base_view) {
|
||||
return base_view;
|
||||
}
|
||||
|
||||
const vk::ImageViewCreateInfo base_view_info = {
|
||||
.image = alloc.image,
|
||||
.viewType = vk::ImageViewType::e2D,
|
||||
.format = instance.GetTraits(pixel_format).native,
|
||||
.subresourceRange{
|
||||
.aspectMask = alloc.aspect,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
base_view = instance.GetDevice().createImageView(base_view_info);
|
||||
return base_view;
|
||||
}
|
||||
|
||||
vk::ImageView Surface::DepthView() noexcept {
|
||||
vk::ImageView& depth_view = alloc.depth_view;
|
||||
if (depth_view) {
|
||||
return depth_view;
|
||||
}
|
||||
|
||||
const vk::ImageViewCreateInfo view_info = {
|
||||
.image = alloc.image,
|
||||
.viewType = vk::ImageViewType::e2D,
|
||||
.format = instance.GetTraits(pixel_format).native,
|
||||
.subresourceRange{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eDepth,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = VK_REMAINING_MIP_LEVELS,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
|
||||
depth_view = instance.GetDevice().createImageView(view_info);
|
||||
return depth_view;
|
||||
}
|
||||
|
||||
vk::ImageView Surface::StencilView() noexcept {
|
||||
vk::ImageView& stencil_view = alloc.stencil_view;
|
||||
if (stencil_view) {
|
||||
return stencil_view;
|
||||
}
|
||||
|
||||
const vk::ImageViewCreateInfo view_info = {
|
||||
.image = alloc.image,
|
||||
.viewType = vk::ImageViewType::e2D,
|
||||
.format = instance.GetTraits(pixel_format).native,
|
||||
.subresourceRange{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eStencil,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = VK_REMAINING_MIP_LEVELS,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
|
||||
stencil_view = instance.GetDevice().createImageView(view_info);
|
||||
return stencil_view;
|
||||
}
|
||||
|
||||
vk::ImageView Surface::StorageView() noexcept {
|
||||
vk::ImageView& storage_view = alloc.storage_view;
|
||||
if (storage_view) {
|
||||
return storage_view;
|
||||
}
|
||||
|
||||
ASSERT_MSG(pixel_format == VideoCore::PixelFormat::RGBA8,
|
||||
"Attempted to retrieve storage view from unsupported surface with format {}",
|
||||
PixelFormatAsString(pixel_format));
|
||||
|
||||
const vk::ImageViewCreateInfo storage_view_info = {
|
||||
.image = alloc.image,
|
||||
.viewType = vk::ImageViewType::e2D,
|
||||
.format = vk::Format::eR32Uint,
|
||||
.subresourceRange{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = VK_REMAINING_MIP_LEVELS,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = VK_REMAINING_ARRAY_LAYERS,
|
||||
},
|
||||
};
|
||||
storage_view = instance.GetDevice().createImageView(storage_view_info);
|
||||
return storage_view;
|
||||
}
|
||||
|
||||
void Surface::ScaledUpload(const VideoCore::BufferTextureCopy& upload, const StagingData& staging) {
|
||||
const u32 rect_width = upload.texture_rect.GetWidth();
|
||||
const u32 rect_height = upload.texture_rect.GetHeight();
|
||||
|
@@ -170,21 +170,6 @@ public:
|
||||
vk::ImageAspectFlags aspect, TextureRuntime& runtime);
|
||||
~Surface() override;
|
||||
|
||||
/// Uploads pixel data in staging to a rectangle region of the surface texture
|
||||
void Upload(const VideoCore::BufferTextureCopy& upload, const StagingData& staging);
|
||||
|
||||
/// Downloads pixel data to staging from a rectangle region of the surface texture
|
||||
void Download(const VideoCore::BufferTextureCopy& download, const StagingData& staging);
|
||||
|
||||
/// Returns the bpp of the internal surface format
|
||||
u32 GetInternalBytesPerPixel() const;
|
||||
|
||||
/// Returns the access flags indicative of the surface
|
||||
vk::AccessFlags AccessFlags() const noexcept;
|
||||
|
||||
/// Returns the pipeline stage flags indicative of the surface
|
||||
vk::PipelineStageFlags PipelineStageFlags() const noexcept;
|
||||
|
||||
/// Returns the surface aspect
|
||||
vk::ImageAspectFlags Aspect() const noexcept {
|
||||
return alloc.aspect;
|
||||
@@ -200,34 +185,32 @@ public:
|
||||
return alloc.image_view;
|
||||
}
|
||||
|
||||
/// Uploads pixel data in staging to a rectangle region of the surface texture
|
||||
void Upload(const VideoCore::BufferTextureCopy& upload, const StagingData& staging);
|
||||
|
||||
/// Downloads pixel data to staging from a rectangle region of the surface texture
|
||||
void Download(const VideoCore::BufferTextureCopy& download, const StagingData& staging);
|
||||
|
||||
/// Returns the bpp of the internal surface format
|
||||
u32 GetInternalBytesPerPixel() const;
|
||||
|
||||
/// Returns the access flags indicative of the surface
|
||||
vk::AccessFlags AccessFlags() const noexcept;
|
||||
|
||||
/// Returns the pipeline stage flags indicative of the surface
|
||||
vk::PipelineStageFlags PipelineStageFlags() const noexcept;
|
||||
|
||||
/// Returns an image view used to create a framebuffer
|
||||
vk::ImageView FramebufferView() noexcept {
|
||||
is_framebuffer = true;
|
||||
return alloc.base_view;
|
||||
}
|
||||
vk::ImageView FramebufferView() noexcept;
|
||||
|
||||
/// Returns the depth only image view of the surface, null otherwise
|
||||
vk::ImageView DepthView() const noexcept {
|
||||
return alloc.depth_view;
|
||||
}
|
||||
/// Returns the depth only image view of the surface
|
||||
vk::ImageView DepthView() noexcept;
|
||||
|
||||
/// Returns the stencil only image view of the surface, null otherwise
|
||||
vk::ImageView StencilView() const noexcept {
|
||||
return alloc.stencil_view;
|
||||
}
|
||||
/// Returns the stencil only image view of the surface
|
||||
vk::ImageView StencilView() noexcept;
|
||||
|
||||
/// Returns the R32 image view used for atomic load/store
|
||||
vk::ImageView StorageView() noexcept {
|
||||
if (!alloc.storage_view) {
|
||||
LOG_CRITICAL(Render_Vulkan,
|
||||
"Surface with pixel format {} and internal format {} "
|
||||
"does not provide requested storage view!",
|
||||
VideoCore::PixelFormatAsString(pixel_format), vk::to_string(alloc.format));
|
||||
UNREACHABLE();
|
||||
}
|
||||
is_storage = true;
|
||||
return alloc.storage_view;
|
||||
}
|
||||
vk::ImageView StorageView() noexcept;
|
||||
|
||||
private:
|
||||
/// Uploads pixel data to scaled texture
|
||||
|
Reference in New Issue
Block a user