VideoCommon: enhance 'CustomResourceManager' for post processing
This expands the interface of 'CustomResourceManager' to get a Material for post processing a frame buffer (currently EFB). The flow is similar to the normal draw material but distinguishes itself by not needing a UID. The full shader is much simpler than the draw shader and is currently put inline with the shader resource.
This commit is contained in:
@@ -43,7 +43,8 @@ void CustomResourceManager::Shutdown()
|
|||||||
|
|
||||||
void CustomResourceManager::Reset()
|
void CustomResourceManager::Reset()
|
||||||
{
|
{
|
||||||
m_material_resources.clear();
|
m_draw_material_resources.clear();
|
||||||
|
m_postprocessing_material_resources.clear();
|
||||||
m_shader_resources.clear();
|
m_shader_resources.clear();
|
||||||
m_texture_data_resources.clear();
|
m_texture_data_resources.clear();
|
||||||
m_texture_sampler_resources.clear();
|
m_texture_sampler_resources.clear();
|
||||||
@@ -102,11 +103,11 @@ TextureDataResource* CustomResourceManager::GetTextureDataFromAsset(
|
|||||||
return resource.get();
|
return resource.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialResource* CustomResourceManager::GetMaterialFromAsset(
|
MaterialResource* CustomResourceManager::GetDrawMaterialFromAsset(
|
||||||
const CustomAssetLibrary::AssetID& asset_id, const GXPipelineUid& pipeline_uid,
|
const CustomAssetLibrary::AssetID& asset_id, const GXPipelineUid& pipeline_uid,
|
||||||
std::shared_ptr<VideoCommon::CustomAssetLibrary> library)
|
std::shared_ptr<VideoCommon::CustomAssetLibrary> library)
|
||||||
{
|
{
|
||||||
auto& resource = m_material_resources[asset_id][PipelineToHash(pipeline_uid)];
|
auto& resource = m_draw_material_resources[asset_id][PipelineToHash(pipeline_uid)];
|
||||||
if (resource == nullptr)
|
if (resource == nullptr)
|
||||||
{
|
{
|
||||||
resource = std::make_unique<MaterialResource>(
|
resource = std::make_unique<MaterialResource>(
|
||||||
@@ -116,11 +117,24 @@ MaterialResource* CustomResourceManager::GetMaterialFromAsset(
|
|||||||
return resource.get();
|
return resource.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderResource*
|
MaterialResource* CustomResourceManager::GetPostProcessingMaterialFromAsset(
|
||||||
CustomResourceManager::GetShaderFromAsset(const CustomAssetLibrary::AssetID& asset_id,
|
const CustomAssetLibrary::AssetID& asset_id,
|
||||||
std::size_t shader_key, const GXPipelineUid& pipeline_uid,
|
std::shared_ptr<VideoCommon::CustomAssetLibrary> library)
|
||||||
const std::string& preprocessor_settings,
|
{
|
||||||
std::shared_ptr<VideoCommon::CustomAssetLibrary> library)
|
auto& resource = m_postprocessing_material_resources[asset_id];
|
||||||
|
if (resource == nullptr)
|
||||||
|
{
|
||||||
|
resource =
|
||||||
|
std::make_unique<MaterialResource>(CreateResourceContext(asset_id, std::move(library)));
|
||||||
|
}
|
||||||
|
resource->Process();
|
||||||
|
return resource.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderResource* CustomResourceManager::GetShaderFromAsset(
|
||||||
|
const CustomAssetLibrary::AssetID& asset_id, std::size_t shader_key,
|
||||||
|
const std::optional<GXPipelineUid>& pipeline_uid, const std::string& preprocessor_settings,
|
||||||
|
std::shared_ptr<VideoCommon::CustomAssetLibrary> library)
|
||||||
{
|
{
|
||||||
auto& resource = m_shader_resources[asset_id][shader_key];
|
auto& resource = m_shader_resources[asset_id][shader_key];
|
||||||
if (resource == nullptr)
|
if (resource == nullptr)
|
||||||
|
|||||||
@@ -37,14 +37,20 @@ public:
|
|||||||
TextureDataResource*
|
TextureDataResource*
|
||||||
GetTextureDataFromAsset(const CustomAssetLibrary::AssetID& asset_id,
|
GetTextureDataFromAsset(const CustomAssetLibrary::AssetID& asset_id,
|
||||||
std::shared_ptr<VideoCommon::CustomAssetLibrary> library);
|
std::shared_ptr<VideoCommon::CustomAssetLibrary> library);
|
||||||
MaterialResource* GetMaterialFromAsset(const CustomAssetLibrary::AssetID& asset_id,
|
MaterialResource*
|
||||||
const GXPipelineUid& pipeline_uid,
|
GetDrawMaterialFromAsset(const CustomAssetLibrary::AssetID& asset_id,
|
||||||
std::shared_ptr<VideoCommon::CustomAssetLibrary> library);
|
const GXPipelineUid& pipeline_uid,
|
||||||
|
std::shared_ptr<VideoCommon::CustomAssetLibrary> library);
|
||||||
|
MaterialResource*
|
||||||
|
GetPostProcessingMaterialFromAsset(const CustomAssetLibrary::AssetID& asset_id,
|
||||||
|
std::shared_ptr<VideoCommon::CustomAssetLibrary> library);
|
||||||
|
|
||||||
ShaderResource* GetShaderFromAsset(const CustomAssetLibrary::AssetID& asset_id,
|
ShaderResource* GetShaderFromAsset(const CustomAssetLibrary::AssetID& asset_id,
|
||||||
std::size_t shader_key, const GXPipelineUid& pipeline_uid,
|
std::size_t shader_key,
|
||||||
|
const std::optional<GXPipelineUid>& pipeline_uid,
|
||||||
const std::string& preprocessor_settings,
|
const std::string& preprocessor_settings,
|
||||||
std::shared_ptr<VideoCommon::CustomAssetLibrary> library);
|
std::shared_ptr<VideoCommon::CustomAssetLibrary> library);
|
||||||
|
|
||||||
TextureAndSamplerResource*
|
TextureAndSamplerResource*
|
||||||
GetTextureAndSamplerFromAsset(const CustomAssetLibrary::AssetID& asset_id,
|
GetTextureAndSamplerFromAsset(const CustomAssetLibrary::AssetID& asset_id,
|
||||||
std::shared_ptr<VideoCommon::CustomAssetLibrary> library);
|
std::shared_ptr<VideoCommon::CustomAssetLibrary> library);
|
||||||
@@ -59,7 +65,7 @@ private:
|
|||||||
std::unique_ptr<AsyncShaderCompiler> m_async_shader_compiler;
|
std::unique_ptr<AsyncShaderCompiler> m_async_shader_compiler;
|
||||||
|
|
||||||
using PipelineIdToMaterial = std::map<std::size_t, std::unique_ptr<MaterialResource>>;
|
using PipelineIdToMaterial = std::map<std::size_t, std::unique_ptr<MaterialResource>>;
|
||||||
std::map<CustomAssetLibrary::AssetID, PipelineIdToMaterial> m_material_resources;
|
std::map<CustomAssetLibrary::AssetID, PipelineIdToMaterial> m_draw_material_resources;
|
||||||
|
|
||||||
using ShaderKeyToShader = std::map<std::size_t, std::unique_ptr<ShaderResource>>;
|
using ShaderKeyToShader = std::map<std::size_t, std::unique_ptr<ShaderResource>>;
|
||||||
std::map<CustomAssetLibrary::AssetID, ShaderKeyToShader> m_shader_resources;
|
std::map<CustomAssetLibrary::AssetID, ShaderKeyToShader> m_shader_resources;
|
||||||
@@ -70,6 +76,9 @@ private:
|
|||||||
std::map<CustomAssetLibrary::AssetID, std::unique_ptr<TextureAndSamplerResource>>
|
std::map<CustomAssetLibrary::AssetID, std::unique_ptr<TextureAndSamplerResource>>
|
||||||
m_texture_sampler_resources;
|
m_texture_sampler_resources;
|
||||||
|
|
||||||
|
std::map<CustomAssetLibrary::AssetID, std::unique_ptr<MaterialResource>>
|
||||||
|
m_postprocessing_material_resources;
|
||||||
|
|
||||||
ShaderHostConfig m_host_config;
|
ShaderHostConfig m_host_config;
|
||||||
|
|
||||||
Common::EventHook m_xfb_event;
|
Common::EventHook m_xfb_event;
|
||||||
|
|||||||
@@ -54,6 +54,13 @@ SamplerState CalculateSamplerAnisotropy(const SamplerState& initial_sampler)
|
|||||||
|
|
||||||
namespace VideoCommon
|
namespace VideoCommon
|
||||||
{
|
{
|
||||||
|
MaterialResource::MaterialResource(Resource::ResourceContext resource_context)
|
||||||
|
: Resource(std::move(resource_context))
|
||||||
|
{
|
||||||
|
m_material_asset = m_resource_context.asset_cache->CreateAsset<MaterialAsset>(
|
||||||
|
m_resource_context.primary_asset_id, m_resource_context.asset_library, this);
|
||||||
|
}
|
||||||
|
|
||||||
MaterialResource::MaterialResource(Resource::ResourceContext resource_context,
|
MaterialResource::MaterialResource(Resource::ResourceContext resource_context,
|
||||||
const GXPipelineUid& pipeline_uid)
|
const GXPipelineUid& pipeline_uid)
|
||||||
: Resource(std::move(resource_context)), m_uid(pipeline_uid)
|
: Resource(std::move(resource_context)), m_uid(pipeline_uid)
|
||||||
@@ -61,8 +68,8 @@ MaterialResource::MaterialResource(Resource::ResourceContext resource_context,
|
|||||||
m_material_asset = m_resource_context.asset_cache->CreateAsset<MaterialAsset>(
|
m_material_asset = m_resource_context.asset_cache->CreateAsset<MaterialAsset>(
|
||||||
m_resource_context.primary_asset_id, m_resource_context.asset_library, this);
|
m_resource_context.primary_asset_id, m_resource_context.asset_library, this);
|
||||||
m_uid_vertex_format_copy =
|
m_uid_vertex_format_copy =
|
||||||
g_gfx->CreateNativeVertexFormat(m_uid.vertex_format->GetVertexDeclaration());
|
g_gfx->CreateNativeVertexFormat(m_uid->vertex_format->GetVertexDeclaration());
|
||||||
m_uid.vertex_format = m_uid_vertex_format_copy.get();
|
m_uid->vertex_format = m_uid_vertex_format_copy.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MaterialResource::ResetData()
|
void MaterialResource::ResetData()
|
||||||
@@ -98,7 +105,7 @@ Resource::TaskComplete MaterialResource::CollectPrimaryData()
|
|||||||
}
|
}
|
||||||
|
|
||||||
CreateTextureData(m_load_data.get());
|
CreateTextureData(m_load_data.get());
|
||||||
SetShaderKey(m_load_data.get(), &m_uid);
|
SetShaderKey(m_load_data.get(), m_uid ? &*m_uid : nullptr);
|
||||||
|
|
||||||
return Resource::TaskComplete::Yes;
|
return Resource::TaskComplete::Yes;
|
||||||
}
|
}
|
||||||
@@ -140,8 +147,18 @@ Resource::TaskComplete MaterialResource::CollectDependencyData()
|
|||||||
|
|
||||||
if (m_load_data->m_material_data->next_material_asset != "")
|
if (m_load_data->m_material_data->next_material_asset != "")
|
||||||
{
|
{
|
||||||
m_load_data->m_next_material = m_resource_context.resource_manager->GetMaterialFromAsset(
|
if (m_uid)
|
||||||
m_load_data->m_material_data->next_material_asset, m_uid, m_resource_context.asset_library);
|
{
|
||||||
|
m_load_data->m_next_material = m_resource_context.resource_manager->GetDrawMaterialFromAsset(
|
||||||
|
m_load_data->m_material_data->next_material_asset, *m_uid,
|
||||||
|
m_resource_context.asset_library);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_load_data->m_next_material =
|
||||||
|
m_resource_context.resource_manager->GetPostProcessingMaterialFromAsset(
|
||||||
|
m_load_data->m_material_data->next_material_asset, m_resource_context.asset_library);
|
||||||
|
}
|
||||||
m_load_data->m_next_material->AddReference(this);
|
m_load_data->m_next_material->AddReference(this);
|
||||||
const auto data_processed = m_load_data->m_next_material->IsDataProcessed();
|
const auto data_processed = m_load_data->m_next_material->IsDataProcessed();
|
||||||
if (data_processed == TaskComplete::Error)
|
if (data_processed == TaskComplete::Error)
|
||||||
@@ -222,33 +239,66 @@ Resource::TaskComplete MaterialResource::ProcessData()
|
|||||||
config.pixel_shader = m_shader_resource_data->GetPixelShader();
|
config.pixel_shader = m_shader_resource_data->GetPixelShader();
|
||||||
config.geometry_shader = m_shader_resource_data->GetGeometryShader();
|
config.geometry_shader = m_shader_resource_data->GetGeometryShader();
|
||||||
|
|
||||||
const auto actual_uid = ApplyDriverBugs(*m_uid);
|
if (m_uid)
|
||||||
|
|
||||||
if (m_material_resource_data->m_material_data->blending_state)
|
|
||||||
config.blending_state = *m_material_resource_data->m_material_data->blending_state;
|
|
||||||
else
|
|
||||||
config.blending_state = actual_uid.blending_state;
|
|
||||||
|
|
||||||
if (m_material_resource_data->m_material_data->depth_state)
|
|
||||||
config.depth_state = *m_material_resource_data->m_material_data->depth_state;
|
|
||||||
else
|
|
||||||
config.depth_state = actual_uid.depth_state;
|
|
||||||
|
|
||||||
config.framebuffer_state = std::move(m_frame_buffer_state);
|
|
||||||
config.framebuffer_state.additional_color_attachment_count = 0;
|
|
||||||
|
|
||||||
config.rasterization_state = actual_uid.rasterization_state;
|
|
||||||
if (m_material_resource_data->m_material_data->cull_mode)
|
|
||||||
{
|
{
|
||||||
config.rasterization_state.cull_mode =
|
// Draw based pipeline
|
||||||
*m_material_resource_data->m_material_data->cull_mode;
|
const auto actual_uid = ApplyDriverBugs(*m_uid);
|
||||||
|
|
||||||
|
if (m_material_resource_data->m_material_data->blending_state)
|
||||||
|
config.blending_state = *m_material_resource_data->m_material_data->blending_state;
|
||||||
|
else
|
||||||
|
config.blending_state = actual_uid.blending_state;
|
||||||
|
|
||||||
|
if (m_material_resource_data->m_material_data->depth_state)
|
||||||
|
config.depth_state = *m_material_resource_data->m_material_data->depth_state;
|
||||||
|
else
|
||||||
|
config.depth_state = actual_uid.depth_state;
|
||||||
|
|
||||||
|
config.framebuffer_state = std::move(m_frame_buffer_state);
|
||||||
|
config.framebuffer_state.additional_color_attachment_count = 0;
|
||||||
|
|
||||||
|
config.rasterization_state = actual_uid.rasterization_state;
|
||||||
|
if (m_material_resource_data->m_material_data->cull_mode)
|
||||||
|
{
|
||||||
|
config.rasterization_state.cull_mode =
|
||||||
|
*m_material_resource_data->m_material_data->cull_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
config.vertex_format = actual_uid.vertex_format;
|
||||||
|
config.usage = AbstractPipelineUsage::GX;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Post processing based pipeline
|
||||||
|
|
||||||
|
// Many of these properties don't make sense to replace but we expose them for draw
|
||||||
|
// based materials, might as well allow them to be used if the user wants
|
||||||
|
|
||||||
|
if (m_material_resource_data->m_material_data->blending_state)
|
||||||
|
config.blending_state = *m_material_resource_data->m_material_data->blending_state;
|
||||||
|
else
|
||||||
|
config.blending_state = RenderState::GetNoBlendingBlendState();
|
||||||
|
|
||||||
|
if (m_material_resource_data->m_material_data->depth_state)
|
||||||
|
config.depth_state = *m_material_resource_data->m_material_data->depth_state;
|
||||||
|
else
|
||||||
|
config.depth_state = RenderState::GetNoDepthTestingDepthState();
|
||||||
|
|
||||||
|
config.framebuffer_state = RenderState::GetRGBA8FramebufferState();
|
||||||
|
|
||||||
|
config.rasterization_state =
|
||||||
|
RenderState::GetNoCullRasterizationState(PrimitiveType::Triangles);
|
||||||
|
if (m_material_resource_data->m_material_data->cull_mode)
|
||||||
|
{
|
||||||
|
config.rasterization_state.cull_mode =
|
||||||
|
*m_material_resource_data->m_material_data->cull_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
config.vertex_format = nullptr;
|
||||||
|
config.usage = AbstractPipelineUsage::Utility;
|
||||||
}
|
}
|
||||||
|
|
||||||
config.vertex_format = actual_uid.vertex_format;
|
|
||||||
config.usage = AbstractPipelineUsage::GX;
|
|
||||||
|
|
||||||
m_material_resource_data->m_pipeline = g_gfx->CreatePipeline(config);
|
m_material_resource_data->m_pipeline = g_gfx->CreatePipeline(config);
|
||||||
|
|
||||||
if (m_material_resource_data->m_pipeline)
|
if (m_material_resource_data->m_pipeline)
|
||||||
{
|
{
|
||||||
WriteUniforms(m_material_resource_data.get());
|
WriteUniforms(m_material_resource_data.get());
|
||||||
@@ -268,7 +318,7 @@ Resource::TaskComplete MaterialResource::ProcessData()
|
|||||||
if (!m_processing_load_data)
|
if (!m_processing_load_data)
|
||||||
{
|
{
|
||||||
auto wi = m_resource_context.shader_compiler->CreateWorkItem<WorkItem>(
|
auto wi = m_resource_context.shader_compiler->CreateWorkItem<WorkItem>(
|
||||||
m_load_data, std::move(shader_data), &m_uid,
|
m_load_data, std::move(shader_data), m_uid ? &*m_uid : nullptr,
|
||||||
g_framebuffer_manager->GetEFBFramebufferState());
|
g_framebuffer_manager->GetEFBFramebufferState());
|
||||||
|
|
||||||
// We don't need priority, that is already handled by the resource system
|
// We don't need priority, that is already handled by the resource system
|
||||||
@@ -360,7 +410,8 @@ void MaterialResource::SetShaderKey(Data* data, GXPipelineUid* uid)
|
|||||||
XXH3_INITSTATE(&shader_key_hash);
|
XXH3_INITSTATE(&shader_key_hash);
|
||||||
XXH3_64bits_reset_withSeed(&shader_key_hash, static_cast<XXH64_hash_t>(1));
|
XXH3_64bits_reset_withSeed(&shader_key_hash, static_cast<XXH64_hash_t>(1));
|
||||||
|
|
||||||
UpdateHashWithPipeline(*uid, &shader_key_hash);
|
if (uid)
|
||||||
|
UpdateHashWithPipeline(*uid, &shader_key_hash);
|
||||||
XXH3_64bits_update(&shader_key_hash, data->m_preprocessor_settings.c_str(),
|
XXH3_64bits_update(&shader_key_hash, data->m_preprocessor_settings.c_str(),
|
||||||
data->m_preprocessor_settings.size());
|
data->m_preprocessor_settings.size());
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -27,6 +28,7 @@ namespace VideoCommon
|
|||||||
class MaterialResource final : public Resource
|
class MaterialResource final : public Resource
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
explicit MaterialResource(Resource::ResourceContext resource_context);
|
||||||
MaterialResource(Resource::ResourceContext resource_context, const GXPipelineUid& pipeline_uid);
|
MaterialResource(Resource::ResourceContext resource_context, const GXPipelineUid& pipeline_uid);
|
||||||
|
|
||||||
struct TextureLikeReference
|
struct TextureLikeReference
|
||||||
@@ -93,7 +95,9 @@ private:
|
|||||||
// Note: asset cache owns the asset, we access as a reference
|
// Note: asset cache owns the asset, we access as a reference
|
||||||
MaterialAsset* m_material_asset = nullptr;
|
MaterialAsset* m_material_asset = nullptr;
|
||||||
|
|
||||||
GXPipelineUid m_uid;
|
// If provided, denotes this material will be used as a custom draw material.
|
||||||
|
// If not provided, denotes this will be used as an efb post processing material.
|
||||||
|
std::optional<GXPipelineUid> m_uid;
|
||||||
std::unique_ptr<NativeVertexFormat> m_uid_vertex_format_copy;
|
std::unique_ptr<NativeVertexFormat> m_uid_vertex_format_copy;
|
||||||
};
|
};
|
||||||
} // namespace VideoCommon
|
} // namespace VideoCommon
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "VideoCommon/AbstractGfx.h"
|
#include "VideoCommon/AbstractGfx.h"
|
||||||
#include "VideoCommon/Assets/CustomAssetCache.h"
|
#include "VideoCommon/Assets/CustomAssetCache.h"
|
||||||
#include "VideoCommon/AsyncShaderCompiler.h"
|
#include "VideoCommon/AsyncShaderCompiler.h"
|
||||||
|
#include "VideoCommon/FramebufferShaderGen.h"
|
||||||
#include "VideoCommon/GeometryShaderGen.h"
|
#include "VideoCommon/GeometryShaderGen.h"
|
||||||
#include "VideoCommon/PipelineUtils.h"
|
#include "VideoCommon/PipelineUtils.h"
|
||||||
#include "VideoCommon/PixelShaderGen.h"
|
#include "VideoCommon/PixelShaderGen.h"
|
||||||
@@ -20,20 +21,223 @@ namespace VideoCommon
|
|||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
std::unique_ptr<AbstractShader>
|
// TODO: the uniform buffer is combined due to the utility path only having a single
|
||||||
CompileGeometryShader(const GeometryShaderUid& uid, APIType api_type, ShaderHostConfig host_config)
|
// set of constants, this isn't ideal (both for the end user, where it's more readable
|
||||||
|
// to see 'custom_uniforms' before variables and from Dolphin because the
|
||||||
|
// standard uniforms have to be packed with the custom ones
|
||||||
|
void GeneratePostProcessUniformOutput(ShaderCode& shader_source, std::string_view block_name,
|
||||||
|
std::string_view uniforms)
|
||||||
{
|
{
|
||||||
const ShaderCode source_code =
|
shader_source.Write("UBO_BINDING(std140, 1) uniform {} {{\n", block_name);
|
||||||
GenerateGeometryShaderCode(api_type, host_config, uid.GetUidData());
|
shader_source.Write("\tvec4 source_resolution;\n");
|
||||||
return g_gfx->CreateShaderFromSource(ShaderStage::Geometry, source_code.GetBuffer(), nullptr,
|
shader_source.Write("\tvec4 target_resolution;\n");
|
||||||
fmt::format("Geometry shader: {}", *uid.GetUidData()));
|
shader_source.Write("\tvec4 window_resolution;\n");
|
||||||
|
shader_source.Write("\tvec4 source_region;\n");
|
||||||
|
shader_source.Write("\tint source_layer;\n");
|
||||||
|
shader_source.Write("\tint source_layer_pad1;\n");
|
||||||
|
shader_source.Write("\tint source_layer_pad2;\n");
|
||||||
|
shader_source.Write("\tint source_layer_pad3;\n");
|
||||||
|
shader_source.Write("\tuint time;\n");
|
||||||
|
shader_source.Write("\tuint time_pad1;\n");
|
||||||
|
shader_source.Write("\tuint time_pad2;\n");
|
||||||
|
shader_source.Write("\tuint time_pad3;\n");
|
||||||
|
shader_source.Write("\tint graphics_api;\n");
|
||||||
|
shader_source.Write("\tint graphics_api_pad1;\n");
|
||||||
|
shader_source.Write("\tint graphics_api_pad2;\n");
|
||||||
|
shader_source.Write("\tint graphics_api_pad3;\n");
|
||||||
|
shader_source.Write("\tuint efb_scale;\n");
|
||||||
|
shader_source.Write("\tuint efb_scale_pad1;\n");
|
||||||
|
shader_source.Write("\tuint efb_scale_pad2;\n");
|
||||||
|
shader_source.Write("\tuint efb_scale_pad3;\n");
|
||||||
|
if (!uniforms.empty())
|
||||||
|
{
|
||||||
|
shader_source.Write("{}", uniforms);
|
||||||
|
}
|
||||||
|
shader_source.Write("}};\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> CompilePixelShader(const PixelShaderUid& uid,
|
// TODO: move this to a more standard post processing file
|
||||||
std::string_view preprocessor_settings,
|
// once post processing has been cleaned up
|
||||||
APIType api_type,
|
void GeneratePostProcessingVertexShader(ShaderCode& shader_source,
|
||||||
const ShaderHostConfig& host_config,
|
const CustomVertexContents& custom_contents)
|
||||||
RasterSurfaceShaderData* shader_data)
|
{
|
||||||
|
// Note: if blocks are the same, they need to match for the OpenGL backend
|
||||||
|
GeneratePostProcessUniformOutput(shader_source, "PSBlock", custom_contents.uniforms);
|
||||||
|
|
||||||
|
// Define some defines that are shared with custom draw shaders,
|
||||||
|
// so that a common shader code could possibly be used in both
|
||||||
|
shader_source.Write("#define HAS_COLOR_0 0\n");
|
||||||
|
shader_source.Write("#define HAS_COLOR_1 0\n");
|
||||||
|
shader_source.Write("#define HAS_NORMAL 0\n");
|
||||||
|
shader_source.Write("#define HAS_BINORMAL 0\n");
|
||||||
|
shader_source.Write("#define HAS_TANGENT 0\n");
|
||||||
|
shader_source.Write("#define HAS_TEXTURE_COORD_0 1\n");
|
||||||
|
for (u32 i = 1; i < 8; i++)
|
||||||
|
{
|
||||||
|
shader_source.Write("#define HAS_TEXTURE_COORD_{} 0\n", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the common structs, might want to consider
|
||||||
|
// moving these to another location?
|
||||||
|
shader_source.Write("struct DolphinVertexInput\n");
|
||||||
|
shader_source.Write("{{\n");
|
||||||
|
shader_source.Write("\tvec4 position;\n");
|
||||||
|
shader_source.Write("\tvec3 texture_coord_0;\n");
|
||||||
|
shader_source.Write("}};\n\n");
|
||||||
|
|
||||||
|
shader_source.Write("struct DolphinVertexOutput\n");
|
||||||
|
shader_source.Write("{{\n");
|
||||||
|
shader_source.Write("\tvec4 position;\n");
|
||||||
|
shader_source.Write("\tvec3 texture_coord_0;\n");
|
||||||
|
shader_source.Write("}};\n\n");
|
||||||
|
|
||||||
|
constexpr std::string_view emulated_vertex_definition =
|
||||||
|
"void dolphin_process_emulated_vertex(in DolphinVertexInput vertex_input, out "
|
||||||
|
"DolphinVertexOutput vertex_output)";
|
||||||
|
shader_source.Write("{}\n", emulated_vertex_definition);
|
||||||
|
shader_source.Write("{{\n");
|
||||||
|
shader_source.Write("\tvertex_output.position = vertex_input.position;\n");
|
||||||
|
shader_source.Write("\tvertex_output.texture_coord_0 = vertex_input.texture_coord_0;\n");
|
||||||
|
shader_source.Write("}}\n");
|
||||||
|
|
||||||
|
if (custom_contents.shader.empty())
|
||||||
|
{
|
||||||
|
shader_source.Write(
|
||||||
|
"void process_vertex(in DolphinVertexInput vertex_input, out DolphinVertexOutput "
|
||||||
|
"vertex_output)\n");
|
||||||
|
shader_source.Write("{{\n");
|
||||||
|
|
||||||
|
shader_source.Write("\tdolphin_process_emulated_vertex(vertex_input, vertex_output);\n");
|
||||||
|
|
||||||
|
shader_source.Write("}}\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shader_source.Write("{}\n", custom_contents.shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_backend_info.bSupportsGeometryShaders)
|
||||||
|
{
|
||||||
|
shader_source.Write("VARYING_LOCATION(0) out VertexData {{\n");
|
||||||
|
shader_source.Write("\tvec3 v_tex0;\n");
|
||||||
|
shader_source.Write("}};\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shader_source.Write("VARYING_LOCATION(0) out vec3 v_tex0;\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
shader_source.Write("void main()\n");
|
||||||
|
shader_source.Write("{{\n");
|
||||||
|
shader_source.Write("\tDolphinVertexInput vertex_input;\n");
|
||||||
|
shader_source.Write("\tvec3 vert = vec3(float((gl_VertexID << 1) & 2), "
|
||||||
|
"float(gl_VertexID & 2), 0.0f);\n");
|
||||||
|
shader_source.Write("\tvertex_input.position = vec4(vert.xy * "
|
||||||
|
"float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n");
|
||||||
|
shader_source.Write("\tvertex_input.texture_coord_0 = vec3(source_region.xy + "
|
||||||
|
"(source_region.zw * vert.xy), 0.0f);\n");
|
||||||
|
shader_source.Write("\tDolphinVertexOutput vertex_output;\n");
|
||||||
|
shader_source.Write("\tprocess_vertex(vertex_input, vertex_output);\n");
|
||||||
|
shader_source.Write("\tgl_Position = vertex_output.position;\n");
|
||||||
|
shader_source.Write("\tv_tex0 = vertex_output.texture_coord_0;\n");
|
||||||
|
|
||||||
|
// NDC space is flipped in Vulkan
|
||||||
|
if (g_backend_info.api_type == APIType::Vulkan)
|
||||||
|
{
|
||||||
|
shader_source.Write("\tgl_Position.y = -gl_Position.y;\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
shader_source.Write("}}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void GeneratePostProcessingPixelShader(ShaderCode& shader_source,
|
||||||
|
const CustomPixelContents& custom_contents)
|
||||||
|
{
|
||||||
|
GeneratePostProcessUniformOutput(shader_source, "PSBlock", custom_contents.uniforms);
|
||||||
|
|
||||||
|
shader_source.Write("SAMPLER_BINDING(0) uniform sampler2DArray samp0;\n");
|
||||||
|
|
||||||
|
if (g_backend_info.bSupportsGeometryShaders)
|
||||||
|
{
|
||||||
|
shader_source.Write("VARYING_LOCATION(0) in VertexData {{\n");
|
||||||
|
shader_source.Write("\tvec3 v_tex0;\n");
|
||||||
|
shader_source.Write("}};\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shader_source.Write("VARYING_LOCATION(0) in float3 v_tex0;\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
shader_source.Write("FRAGMENT_OUTPUT_LOCATION(0) out vec4 ocol0;\n");
|
||||||
|
|
||||||
|
shader_source.Write("struct DolphinFragmentInput\n");
|
||||||
|
shader_source.Write("{{\n");
|
||||||
|
for (u32 i = 0; i < 1; i++)
|
||||||
|
{
|
||||||
|
shader_source.Write("\tvec3 tex{};\n", i);
|
||||||
|
}
|
||||||
|
shader_source.Write("\n");
|
||||||
|
|
||||||
|
shader_source.Write("}};\n\n");
|
||||||
|
|
||||||
|
shader_source.Write("struct DolphinFragmentOutput\n");
|
||||||
|
shader_source.Write("{{\n");
|
||||||
|
shader_source.Write("\tvec4 main;\n");
|
||||||
|
shader_source.Write("}};\n\n");
|
||||||
|
|
||||||
|
constexpr std::string_view emulated_fragment_definition =
|
||||||
|
"void dolphin_process_emulated_fragment(in DolphinFragmentInput frag_input, out "
|
||||||
|
"DolphinFragmentOutput frag_output)";
|
||||||
|
shader_source.Write("{}\n", emulated_fragment_definition);
|
||||||
|
shader_source.Write("{{\n");
|
||||||
|
shader_source.Write("\tfrag_output.main = texture(samp0, frag_input.tex0);\n");
|
||||||
|
shader_source.Write("}}\n");
|
||||||
|
|
||||||
|
if (custom_contents.shader.empty())
|
||||||
|
{
|
||||||
|
shader_source.Write(
|
||||||
|
"void process_fragment(in DolphinFragmentInput frag_input, out DolphinFragmentOutput "
|
||||||
|
"frag_output)\n");
|
||||||
|
shader_source.Write("{{\n");
|
||||||
|
|
||||||
|
shader_source.Write("\tdolphin_process_emulated_fragment(frag_input, frag_output);\n");
|
||||||
|
|
||||||
|
shader_source.Write("}}\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shader_source.Write("{}\n", custom_contents.shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
shader_source.Write("void main()\n");
|
||||||
|
shader_source.Write("{{\n");
|
||||||
|
shader_source.Write("\tDolphinFragmentInput frag_input;\n");
|
||||||
|
shader_source.Write("\tfrag_input.tex0 = v_tex0;\n");
|
||||||
|
shader_source.Write("\tDolphinFragmentOutput frag_output;\n");
|
||||||
|
shader_source.Write("\tprocess_fragment(frag_input, frag_output);\n");
|
||||||
|
shader_source.Write("\tocol0 = frag_output.main;\n");
|
||||||
|
shader_source.Write("}}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<AbstractShader> CompileGeometryShader(GeometryShaderUid* uid, APIType api_type,
|
||||||
|
ShaderHostConfig host_config)
|
||||||
|
{
|
||||||
|
if (!uid)
|
||||||
|
{
|
||||||
|
return g_gfx->CreateShaderFromSource(
|
||||||
|
ShaderStage::Geometry, FramebufferShaderGen::GeneratePassthroughGeometryShader(1, 0),
|
||||||
|
nullptr, "Custom Post Processing Geometry Shader");
|
||||||
|
}
|
||||||
|
|
||||||
|
const ShaderCode source_code =
|
||||||
|
GenerateGeometryShaderCode(api_type, host_config, uid->GetUidData());
|
||||||
|
return g_gfx->CreateShaderFromSource(ShaderStage::Geometry, source_code.GetBuffer(), nullptr,
|
||||||
|
fmt::format("Geometry shader: {}", *uid->GetUidData()));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<AbstractShader>
|
||||||
|
CompilePixelShader(PixelShaderUid* uid, std::string_view preprocessor_settings, APIType api_type,
|
||||||
|
const ShaderHostConfig& host_config, RasterSurfaceShaderData* shader_data)
|
||||||
{
|
{
|
||||||
ShaderCode shader_code;
|
ShaderCode shader_code;
|
||||||
|
|
||||||
@@ -89,19 +293,25 @@ std::unique_ptr<AbstractShader> CompilePixelShader(const PixelShaderUid& uid,
|
|||||||
// Compile the shader
|
// Compile the shader
|
||||||
CustomPixelContents contents{.shader = shader_code.GetBuffer(),
|
CustomPixelContents contents{.shader = shader_code.GetBuffer(),
|
||||||
.uniforms = uniform_code.GetBuffer()};
|
.uniforms = uniform_code.GetBuffer()};
|
||||||
const ShaderCode source_code =
|
|
||||||
GeneratePixelShaderCode(api_type, host_config, uid.GetUidData(), contents);
|
ShaderCode source_code;
|
||||||
|
if (uid)
|
||||||
|
{
|
||||||
|
source_code = GeneratePixelShaderCode(api_type, host_config, uid->GetUidData(), contents);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GeneratePostProcessingPixelShader(source_code, contents);
|
||||||
|
}
|
||||||
ShaderIncluder* shader_includer =
|
ShaderIncluder* shader_includer =
|
||||||
shader_data->shader_includer ? &*shader_data->shader_includer : nullptr;
|
shader_data->shader_includer ? &*shader_data->shader_includer : nullptr;
|
||||||
return g_gfx->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer(), shader_includer,
|
return g_gfx->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer(), shader_includer,
|
||||||
"Custom Pixel Shader");
|
"Custom Pixel Shader");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<AbstractShader> CompileVertexShader(const VertexShaderUid& uid,
|
std::unique_ptr<AbstractShader>
|
||||||
std::string_view preprocessor_settings,
|
CompileVertexShader(VertexShaderUid* uid, std::string_view preprocessor_settings, APIType api_type,
|
||||||
APIType api_type,
|
const ShaderHostConfig& host_config, const RasterSurfaceShaderData& shader_data)
|
||||||
const ShaderHostConfig& host_config,
|
|
||||||
const RasterSurfaceShaderData& shader_data)
|
|
||||||
{
|
{
|
||||||
ShaderCode shader_code;
|
ShaderCode shader_code;
|
||||||
|
|
||||||
@@ -157,14 +367,22 @@ std::unique_ptr<AbstractShader> CompileVertexShader(const VertexShaderUid& uid,
|
|||||||
// Compile the shader
|
// Compile the shader
|
||||||
CustomVertexContents contents{.shader = shader_code.GetBuffer(),
|
CustomVertexContents contents{.shader = shader_code.GetBuffer(),
|
||||||
.uniforms = uniform_code.GetBuffer()};
|
.uniforms = uniform_code.GetBuffer()};
|
||||||
const ShaderCode source_code =
|
|
||||||
GenerateVertexShaderCode(api_type, host_config, uid.GetUidData(), contents);
|
ShaderCode source_code;
|
||||||
|
if (uid)
|
||||||
|
{
|
||||||
|
source_code = GenerateVertexShaderCode(api_type, host_config, uid->GetUidData(), contents);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GeneratePostProcessingVertexShader(source_code, contents);
|
||||||
|
}
|
||||||
return g_gfx->CreateShaderFromSource(ShaderStage::Vertex, source_code.GetBuffer(), nullptr,
|
return g_gfx->CreateShaderFromSource(ShaderStage::Vertex, source_code.GetBuffer(), nullptr,
|
||||||
"Custom Vertex Shader");
|
"Custom Vertex Shader");
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
ShaderResource::ShaderResource(Resource::ResourceContext resource_context,
|
ShaderResource::ShaderResource(Resource::ResourceContext resource_context,
|
||||||
const GXPipelineUid& pipeline_uid,
|
const std::optional<GXPipelineUid>& pipeline_uid,
|
||||||
const std::string& preprocessor_setting,
|
const std::string& preprocessor_setting,
|
||||||
const ShaderHostConfig& shader_host_config)
|
const ShaderHostConfig& shader_host_config)
|
||||||
: Resource(std::move(resource_context)), m_shader_host_config{.bits = shader_host_config.bits},
|
: Resource(std::move(resource_context)), m_shader_host_config{.bits = shader_host_config.bits},
|
||||||
@@ -257,24 +475,46 @@ Resource::TaskComplete ShaderResource::ProcessData()
|
|||||||
bool Compile() override
|
bool Compile() override
|
||||||
{
|
{
|
||||||
const ShaderHostConfig shader_host_config{.bits = m_shader_bits};
|
const ShaderHostConfig shader_host_config{.bits = m_shader_bits};
|
||||||
auto actual_uid = ApplyDriverBugs(*m_uid);
|
if (m_uid)
|
||||||
|
|
||||||
ClearUnusedPixelShaderUidBits(g_backend_info.api_type, shader_host_config,
|
|
||||||
&actual_uid.ps_uid);
|
|
||||||
m_resource_data->m_needs_geometry_shader = shader_host_config.backend_geometry_shaders &&
|
|
||||||
!actual_uid.gs_uid.GetUidData()->IsPassthrough();
|
|
||||||
|
|
||||||
if (m_resource_data->m_needs_geometry_shader)
|
|
||||||
{
|
{
|
||||||
m_resource_data->m_geometry_shader =
|
// Draw based shader
|
||||||
CompileGeometryShader(actual_uid.gs_uid, g_backend_info.api_type, shader_host_config);
|
auto actual_uid = ApplyDriverBugs(*m_uid);
|
||||||
|
|
||||||
|
ClearUnusedPixelShaderUidBits(g_backend_info.api_type, shader_host_config,
|
||||||
|
&actual_uid.ps_uid);
|
||||||
|
m_resource_data->m_needs_geometry_shader = shader_host_config.backend_geometry_shaders &&
|
||||||
|
!actual_uid.gs_uid.GetUidData()->IsPassthrough();
|
||||||
|
|
||||||
|
if (m_resource_data->m_needs_geometry_shader)
|
||||||
|
{
|
||||||
|
m_resource_data->m_geometry_shader = CompileGeometryShader(
|
||||||
|
&actual_uid.gs_uid, g_backend_info.api_type, shader_host_config);
|
||||||
|
}
|
||||||
|
m_resource_data->m_pixel_shader =
|
||||||
|
CompilePixelShader(&actual_uid.ps_uid, m_preprocessor_settings, g_backend_info.api_type,
|
||||||
|
shader_host_config, m_resource_data->m_shader_data.get());
|
||||||
|
m_resource_data->m_vertex_shader = CompileVertexShader(
|
||||||
|
&actual_uid.vs_uid, m_preprocessor_settings, g_backend_info.api_type,
|
||||||
|
shader_host_config, *m_resource_data->m_shader_data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Post processing based shader
|
||||||
|
|
||||||
|
m_resource_data->m_needs_geometry_shader =
|
||||||
|
shader_host_config.backend_geometry_shaders && shader_host_config.stereo;
|
||||||
|
if (m_resource_data->m_needs_geometry_shader)
|
||||||
|
{
|
||||||
|
m_resource_data->m_geometry_shader =
|
||||||
|
CompileGeometryShader(nullptr, g_backend_info.api_type, shader_host_config);
|
||||||
|
}
|
||||||
|
m_resource_data->m_pixel_shader =
|
||||||
|
CompilePixelShader(nullptr, m_preprocessor_settings, g_backend_info.api_type,
|
||||||
|
shader_host_config, m_resource_data->m_shader_data.get());
|
||||||
|
m_resource_data->m_vertex_shader =
|
||||||
|
CompileVertexShader(nullptr, m_preprocessor_settings, g_backend_info.api_type,
|
||||||
|
shader_host_config, *m_resource_data->m_shader_data);
|
||||||
}
|
}
|
||||||
m_resource_data->m_pixel_shader =
|
|
||||||
CompilePixelShader(actual_uid.ps_uid, m_preprocessor_settings, g_backend_info.api_type,
|
|
||||||
shader_host_config, m_resource_data->m_shader_data.get());
|
|
||||||
m_resource_data->m_vertex_shader =
|
|
||||||
CompileVertexShader(actual_uid.vs_uid, m_preprocessor_settings, g_backend_info.api_type,
|
|
||||||
shader_host_config, *m_resource_data->m_shader_data);
|
|
||||||
m_resource_data->m_processing_finished = true;
|
m_resource_data->m_processing_finished = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -291,7 +531,7 @@ Resource::TaskComplete ShaderResource::ProcessData()
|
|||||||
{
|
{
|
||||||
std::string_view preprocessor_settings = m_preprocessor_settings;
|
std::string_view preprocessor_settings = m_preprocessor_settings;
|
||||||
auto wi = m_resource_context.shader_compiler->CreateWorkItem<WorkItem>(
|
auto wi = m_resource_context.shader_compiler->CreateWorkItem<WorkItem>(
|
||||||
m_load_data, &m_uid, m_shader_host_config.bits, preprocessor_settings);
|
m_load_data, m_uid ? &*m_uid : nullptr, m_shader_host_config.bits, preprocessor_settings);
|
||||||
|
|
||||||
// We don't need priority, that is already handled by the resource system
|
// We don't need priority, that is already handled by the resource system
|
||||||
m_resource_context.shader_compiler->QueueWorkItem(std::move(wi), 0);
|
m_resource_context.shader_compiler->QueueWorkItem(std::move(wi), 0);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include "VideoCommon/Resources/Resource.h"
|
#include "VideoCommon/Resources/Resource.h"
|
||||||
|
|
||||||
@@ -16,7 +17,8 @@ namespace VideoCommon
|
|||||||
class ShaderResource final : public Resource
|
class ShaderResource final : public Resource
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ShaderResource(Resource::ResourceContext resource_context, const GXPipelineUid& pipeline_uid,
|
ShaderResource(Resource::ResourceContext resource_context,
|
||||||
|
const std::optional<GXPipelineUid>& pipeline_uid,
|
||||||
const std::string& preprocessor_settings,
|
const std::string& preprocessor_settings,
|
||||||
const ShaderHostConfig& shader_host_config);
|
const ShaderHostConfig& shader_host_config);
|
||||||
|
|
||||||
@@ -61,7 +63,10 @@ private:
|
|||||||
bool m_processing_load_data = false;
|
bool m_processing_load_data = false;
|
||||||
|
|
||||||
ShaderHostConfig m_shader_host_config;
|
ShaderHostConfig m_shader_host_config;
|
||||||
GXPipelineUid m_uid;
|
|
||||||
|
// If provided, denotes this shader will be used as a custom draw shader.
|
||||||
|
// If not provided, denotes this will be used as an efb post processing shader.
|
||||||
|
std::optional<GXPipelineUid> m_uid;
|
||||||
std::string m_preprocessor_settings;
|
std::string m_preprocessor_settings;
|
||||||
};
|
};
|
||||||
} // namespace VideoCommon
|
} // namespace VideoCommon
|
||||||
|
|||||||
Reference in New Issue
Block a user