vk: Implement 2D array textures required for new font subsystem

This commit is contained in:
kd-11 2020-02-19 18:50:32 +03:00 committed by kd-11
parent 1df1ceb4ea
commit 6220206cbc
6 changed files with 160 additions and 57 deletions

View file

@ -25,7 +25,7 @@ namespace vk
for (auto &e : image_list)
{
const VkImageSubresourceRange subres = { e->aspect(), 0, 1, 0, 1 };
image_views.push_back(std::make_unique<vk::image_view>(dev, e, vk::default_component_map(), subres));
image_views.push_back(std::make_unique<vk::image_view>(dev, e, VK_IMAGE_VIEW_TYPE_2D, vk::default_component_map(), subres));
}
auto value = std::make_unique<vk::framebuffer_holder>(dev, renderpass, width, height, std::move(image_views));

View file

@ -230,6 +230,22 @@ namespace vk
fmt::throw_exception("Unknown cull face value: 0x%x" HERE, static_cast<u32>(cfv));
}
}
VkImageViewType get_view_type(rsx::texture_dimension_extended type)
{
switch (type)
{
case rsx::texture_dimension_extended::texture_dimension_1d:
return VK_IMAGE_VIEW_TYPE_1D;
case rsx::texture_dimension_extended::texture_dimension_2d:
return VK_IMAGE_VIEW_TYPE_2D;
case rsx::texture_dimension_extended::texture_dimension_cubemap:
return VK_IMAGE_VIEW_TYPE_CUBE;
case rsx::texture_dimension_extended::texture_dimension_3d:
return VK_IMAGE_VIEW_TYPE_3D;
default: ASSUME(0);
};
}
}
namespace
@ -1669,14 +1685,15 @@ void VKGSRender::end()
}
else
{
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
const VkImageViewType view_type = vk::get_view_type(current_fragment_program.get_texture_dimension(i));
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
i,
::glsl::program_domain::glsl_fragment_program,
m_current_frame->descriptor_set);
if (current_fragment_program.redirected_textures & (1 << i))
{
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
i,
::glsl::program_domain::glsl_fragment_program,
m_current_frame->descriptor_set,
@ -1692,7 +1709,8 @@ void VKGSRender::end()
{
if (!rsx::method_registers.vertex_textures[i].enabled())
{
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
const auto view_type = vk::get_view_type(current_vertex_program.get_texture_dimension(i));
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
i,
::glsl::program_domain::glsl_vertex_program,
m_current_frame->descriptor_set);
@ -1712,7 +1730,9 @@ void VKGSRender::end()
if (!image_ptr)
{
rsx_log.error("Texture upload failed to vtexture index %d. Binding null sampler.", i);
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
const auto view_type = vk::get_view_type(current_vertex_program.get_texture_dimension(i));
m_program->bind_uniform({ vk::null_sampler(), vk::null_image_view(*m_current_command_buffer, view_type)->value, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL },
i,
::glsl::program_domain::glsl_vertex_program,
m_current_frame->descriptor_set);

View file

@ -67,8 +67,8 @@ namespace vk
const render_device* g_current_renderer;
std::unique_ptr<image> g_null_texture;
std::unique_ptr<image_view> g_null_image_view;
std::unique_ptr<buffer> g_scratch_buffer;
std::unordered_map<VkImageViewType, std::unique_ptr<image_view>> g_null_image_views;
std::unordered_map<u32, std::unique_ptr<image>> g_typeless_textures;
std::unordered_map<u32, std::unique_ptr<vk::compute_task>> g_compute_tasks;
@ -289,26 +289,32 @@ namespace vk
return g_null_sampler;
}
vk::image_view* null_image_view(vk::command_buffer &cmd)
vk::image_view* null_image_view(vk::command_buffer &cmd, VkImageViewType type)
{
if (g_null_image_view)
return g_null_image_view.get();
if (auto found = g_null_image_views.find(type);
found != g_null_image_views.end())
{
return found->second.get();
}
g_null_texture = std::make_unique<image>(*g_current_renderer, g_current_renderer->get_memory_mapping().device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
VK_IMAGE_TYPE_2D, VK_FORMAT_B8G8R8A8_UNORM, 4, 4, 1, 1, 1, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 0);
if (!g_null_texture)
{
g_null_texture = std::make_unique<image>(*g_current_renderer, g_current_renderer->get_memory_mapping().device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
VK_IMAGE_TYPE_2D, VK_FORMAT_B8G8R8A8_UNORM, 4, 4, 1, 1, 1, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, 0);
g_null_image_view = std::make_unique<image_view>(*g_current_renderer, g_null_texture.get());
// Initialize memory to transparent black
VkClearColorValue clear_color = {};
VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
change_image_layout(cmd, g_null_texture.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, range);
vkCmdClearColorImage(cmd, g_null_texture->value, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_color, 1, &range);
// Initialize memory to transparent black
VkClearColorValue clear_color = {};
VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
change_image_layout(cmd, g_null_texture.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, range);
vkCmdClearColorImage(cmd, g_null_texture->value, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_color, 1, &range);
// Prep for shader access
change_image_layout(cmd, g_null_texture.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, range);
}
// Prep for shader access
change_image_layout(cmd, g_null_texture.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, range);
return g_null_image_view.get();
auto& ret = g_null_image_views[type] = std::make_unique<image_view>(*g_current_renderer, g_null_texture.get(), type);
return ret.get();
}
vk::image* get_typeless_helper(VkFormat format, u32 requested_width, u32 requested_height)
@ -396,7 +402,7 @@ namespace vk
vk::get_resource_manager()->destroy();
g_null_texture.reset();
g_null_image_view.reset();
g_null_image_views.clear();
g_scratch_buffer.reset();
g_upload_heap.destroy();

View file

@ -141,7 +141,7 @@ namespace vk
VkImageAspectFlags get_aspect_flags(VkFormat format);
VkSampler null_sampler();
image_view* null_image_view(vk::command_buffer&);
image_view* null_image_view(vk::command_buffer&, VkImageViewType type);
image* get_typeless_helper(VkFormat format, u32 requested_width, u32 requested_height);
buffer* get_scratch_buffer(u32 min_required_size = 0);
data_heap* get_upload_heap();
@ -1387,6 +1387,11 @@ private:
return info.mipLevels;
}
u32 layers() const
{
return info.arrayLayers;
}
u8 samples() const
{
return u8(info.samples);
@ -1456,8 +1461,9 @@ private:
}
image_view(VkDevice dev, vk::image* resource,
const VkComponentMapping mapping = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A },
const VkImageSubresourceRange range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1})
VkImageViewType view_type = VK_IMAGE_VIEW_TYPE_MAX_ENUM,
const VkComponentMapping& mapping = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A },
const VkImageSubresourceRange& range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1})
: m_device(dev), m_resource(resource)
{
info.format = resource->info.format;
@ -1466,23 +1472,34 @@ private:
info.components = mapping;
info.subresourceRange = range;
switch (resource->info.imageType)
if (view_type == VK_IMAGE_VIEW_TYPE_MAX_ENUM)
{
case VK_IMAGE_TYPE_1D:
info.viewType = VK_IMAGE_VIEW_TYPE_1D;
break;
case VK_IMAGE_TYPE_2D:
if (resource->info.flags == VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT)
info.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
else
info.viewType = VK_IMAGE_VIEW_TYPE_2D;
break;
case VK_IMAGE_TYPE_3D:
info.viewType = VK_IMAGE_VIEW_TYPE_3D;
break;
default:
ASSUME(0);
break;
switch (resource->info.imageType)
{
case VK_IMAGE_TYPE_1D:
info.viewType = VK_IMAGE_VIEW_TYPE_1D;
break;
case VK_IMAGE_TYPE_2D:
if (resource->info.flags == VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT)
info.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
else if (resource->info.arrayLayers == 1)
info.viewType = VK_IMAGE_VIEW_TYPE_2D;
else
info.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY;
break;
case VK_IMAGE_TYPE_3D:
info.viewType = VK_IMAGE_VIEW_TYPE_3D;
break;
default:
ASSUME(0);
break;
}
info.subresourceRange.layerCount = resource->info.arrayLayers;
}
else
{
info.viewType = view_type;
}
create_impl();
@ -1588,7 +1605,7 @@ private:
const auto range = vk::get_image_subresource_range(0, 0, info.arrayLayers, info.mipLevels, aspect() & mask);
verify(HERE), range.aspectMask;
auto view = std::make_unique<vk::image_view>(*get_current_renderer(), this, real_mapping, range);
auto view = std::make_unique<vk::image_view>(*get_current_renderer(), this, VK_IMAGE_VIEW_TYPE_MAX_ENUM, real_mapping, range);
auto result = view.get();
views.emplace(remap_encoding, std::move(view));

View file

@ -4,6 +4,7 @@
#include "VKFragmentProgram.h"
#include "VKRenderTargets.h"
#include "VKFramebuffer.h"
#include "VKResourceManager.h"
#include "../Overlays/overlays.h"
@ -529,6 +530,7 @@ namespace vk
"#version 420\n"
"#extension GL_ARB_separate_shader_objects : enable\n"
"layout(set=0, binding=1) uniform sampler2D fs0;\n"
"layout(set=0, binding=2) uniform sampler2DArray fs1;\n"
"layout(location=0) in vec2 tc0;\n"
"layout(location=1) in vec4 color;\n"
"layout(location=2) in vec4 parameters;\n"
@ -602,16 +604,29 @@ namespace vk
" diff_color.a *= (sin(parameters.x) + 1.f) * 0.5f;\n"
"\n"
" if (parameters.z < 1.)\n"
" {\n"
" ocol = diff_color;\n"
" }\n"
" else if (parameters.z > 2.)\n"
" {\n"
" ocol = texture(fs1, vec3(tc0.x, fract(tc0.y), trunc(tc0.y))).rrrr * diff_color;\n"
" }\n"
" else if (parameters.z > 1.)\n"
" {\n"
" ocol = texture(fs0, tc0).rrrr * diff_color;\n"
" }\n"
" else\n"
" {\n"
" ocol = sample_image(fs0, tc0, parameters2.x).bgra * diff_color;\n"
" }\n"
"}\n";
// Allow mixed primitive rendering
multi_primitive = true;
// 2 input textures
m_num_usable_samplers = 2;
renderpass_config.set_attachment_count(1);
renderpass_config.set_color_mask(0, true, true, true, true);
renderpass_config.set_depth_mask(false);
@ -622,18 +637,18 @@ namespace vk
}
vk::image_view* upload_simple_texture(vk::render_device &dev, vk::command_buffer &cmd,
vk::data_heap& upload_heap, u64 key, int w, int h, bool font, bool temp, void *pixel_src, u32 owner_uid)
vk::data_heap& upload_heap, u64 key, u32 w, u32 h, u32 layers, bool font, bool temp, void *pixel_src, u32 owner_uid)
{
const VkFormat format = (font) ? VK_FORMAT_R8_UNORM : VK_FORMAT_B8G8R8A8_UNORM;
const u32 pitch = (font) ? w : w * 4;
const u32 data_size = pitch * h;
const u32 data_size = pitch * h * layers;
const auto offset = upload_heap.alloc<512>(data_size);
const auto addr = upload_heap.map(offset, data_size);
const VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
const VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, layers };
auto tex = std::make_unique<vk::image>(dev, dev.get_memory_mapping().device_local, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
VK_IMAGE_TYPE_2D, format, std::max(w, 1), std::max(h, 1), 1, 1, 1, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_TYPE_2D, format, std::max(w, 1u), std::max(h, 1u), 1, 1, layers, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
0);
@ -645,12 +660,12 @@ namespace vk
upload_heap.unmap();
VkBufferImageCopy region;
region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 };
region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, layers };
region.bufferOffset = offset;
region.bufferRowLength = w;
region.bufferImageHeight = h;
region.imageOffset = {};
region.imageExtent = { static_cast<u32>(w), static_cast<u32>(h), 1u};
region.imageExtent = { static_cast<u32>(w), static_cast<u32>(h), 1u };
change_image_layout(cmd, tex.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, range);
vkCmdCopyBufferToImage(cmd, upload_heap.heap->value, tex->value, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
@ -686,7 +701,7 @@ namespace vk
u64 storage_key = 1;
for (const auto &res : configuration.texture_raw_data)
{
upload_simple_texture(dev, cmd, upload_heap, storage_key++, res->w, res->h, false, false, res->data, UINT32_MAX);
upload_simple_texture(dev, cmd, upload_heap, storage_key++, res->w, res->h, 1, false, false, res->data, UINT32_MAX);
}
configuration.free_resources();
@ -724,14 +739,33 @@ namespace vk
vk::image_view* find_font(rsx::overlays::font *font, vk::command_buffer &cmd, vk::data_heap &upload_heap)
{
const auto image_size = font->get_glyph_data_dimensions();
u64 key = reinterpret_cast<u64>(font);
auto found = view_cache.find(key);
if (found != view_cache.end())
return found->second.get();
{
if (const auto raw = found->second->image();
image_size.width == raw->width() &&
image_size.height == raw->height() &&
image_size.depth == raw->layers())
{
return found->second.get();
}
else
{
auto gc = vk::get_resource_manager();
gc->dispose(font_cache[key]);
gc->dispose(view_cache[key]);
}
}
//Create font file
return upload_simple_texture(cmd.get_command_pool().get_owner(), cmd, upload_heap, key, font->width, font->height,
true, false, font->glyph_data.data(), UINT32_MAX);
// Create font resource
std::vector<u8> bytes;
font->get_glyph_data(bytes);
return upload_simple_texture(cmd.get_command_pool().get_owner(), cmd, upload_heap, key, image_size.width, image_size.height, image_size.depth,
true, false, bytes.data(), UINT32_MAX);
}
vk::image_view* find_temp_image(rsx::overlays::image_info *desc, vk::command_buffer &cmd, vk::data_heap &upload_heap, u32 owner_uid)
@ -741,7 +775,7 @@ namespace vk
if (found != temp_view_cache.end())
return found->second.get();
return upload_simple_texture(cmd.get_command_pool().get_owner(), cmd, upload_heap, key, desc->w, desc->h,
return upload_simple_texture(cmd.get_command_pool().get_owner(), cmd, upload_heap, key, desc->w, desc->h, 1,
false, true, desc->data, owner_uid);
}
@ -834,6 +868,12 @@ namespace vk
m_time = static_cast<f32>(get_system_time() / 1000) * 0.005f;
m_viewport = { { static_cast<f32>(viewport.x1), static_cast<f32>(viewport.y1) }, { static_cast<f32>(viewport.width()), static_cast<f32>(viewport.height()) } };
std::vector<vk::image_view*> image_views
{
vk::null_image_view(cmd, VK_IMAGE_VIEW_TYPE_2D),
vk::null_image_view(cmd, VK_IMAGE_VIEW_TYPE_2D_ARRAY)
};
for (auto &command : ui.get_compiled().draw_commands)
{
num_drawable_elements = static_cast<u32>(command.verts.size());
@ -850,7 +890,7 @@ namespace vk
m_clip_region = command.config.clip_rect;
m_texture_type = 1;
auto src = vk::null_image_view(cmd);
vk::image_view* src = nullptr;
switch (command.config.texture_ref)
{
case rsx::overlays::image_resource_id::game_icon:
@ -860,8 +900,8 @@ namespace vk
m_skip_texture_read = true;
break;
case rsx::overlays::image_resource_id::font_file:
m_texture_type = 2;
src = find_font(command.config.font_ref, cmd, upload_heap);
m_texture_type = src->image()->layers() == 1 ? 2 : 3;
break;
case rsx::overlays::image_resource_id::raw_image:
src = find_temp_image(static_cast<rsx::overlays::image_info*>(command.config.external_data_ref), cmd, upload_heap, ui.uid);
@ -871,7 +911,13 @@ namespace vk
break;
}
overlay_pass::run(cmd, viewport, target, { src }, render_pass);
if (src)
{
const int res_id = src->image()->layers() > 1 ? 1 : 0;
image_views[res_id] = src;
}
overlay_pass::run(cmd, viewport, target, image_views, render_pass);
}
ui.update();

View file

@ -12,6 +12,8 @@ namespace vk
u64 eid;
const vk::render_device* m_device;
std::vector<std::unique_ptr<vk::buffer>> m_disposed_buffers;
std::vector<std::unique_ptr<vk::image_view>> m_disposed_image_views;
std::vector<std::unique_ptr<vk::image>> m_disposed_images;
rsx::simple_array<VkEvent> m_disposed_events;
eid_scope_t(u64 _eid):
@ -36,6 +38,8 @@ namespace vk
}
m_disposed_buffers.clear();
m_disposed_image_views.clear();
m_disposed_images.clear();
}
};
@ -132,6 +136,16 @@ namespace vk
get_current_eid_scope().m_disposed_buffers.emplace_back(std::move(buf));
}
void dispose(std::unique_ptr<vk::image_view>& view)
{
get_current_eid_scope().m_disposed_image_views.emplace_back(std::move(view));
}
void dispose(std::unique_ptr<vk::image>& img)
{
get_current_eid_scope().m_disposed_images.emplace_back(std::move(img));
}
void dispose(VkEvent& event)
{
get_current_eid_scope().m_disposed_events.push_back(event);