video_core: Commonise rasterizer class

* Also added some comments providing some details about attribute loaders
This commit is contained in:
emufan4568
2022-08-09 18:56:14 +03:00
parent 1ded25f68b
commit 2397c82b85
16 changed files with 549 additions and 695 deletions

View File

@@ -72,6 +72,9 @@ public:
return Vec2{f, f};
}
// Default comparison operators
[[nodiscard]] auto operator<=>(const Vec2& other) const = default;
[[nodiscard]] constexpr Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const {
return {x + other.x, y + other.y};
}
@@ -230,6 +233,9 @@ public:
return Vec3(f, f, f);
}
// Default comparison operators
[[nodiscard]] auto operator<=>(const Vec3& other) const = default;
[[nodiscard]] constexpr Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const {
return {x + other.x, y + other.y, z + other.z};
}
@@ -452,6 +458,9 @@ public:
return Vec4(f, f, f, f);
}
// Default comparison operators
[[nodiscard]] auto operator<=>(const Vec4& other) const = default;
[[nodiscard]] constexpr Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const {
return {x + other.x, y + other.y, z + other.z, w + other.w};
}

View File

@@ -42,15 +42,19 @@ public:
// Creates a backend specific shader object
virtual ShaderHandle CreateShader(ShaderStage stage, std::string_view name, std::string source) = 0;
// Binds a vertex buffer at a provided offset
virtual void BindVertexBuffer(BufferHandle buffer, std::span<const u32> offsets) = 0;
// Binds an index buffer at provided offset
virtual void BindIndexBuffer(BufferHandle buffer, AttribType index_type, u32 offset) = 0;
// Start a draw operation
virtual void Draw(PipelineHandle pipeline, FramebufferHandle draw_framebuffer,
BufferHandle vertex_buffer,
u32 base_vertex, u32 num_vertices) = 0;
virtual void Draw(PipelineHandle pipeline, FramebufferHandle draw_framebuffer, u32 base_vertex,
u32 num_vertices) = 0;
// Start an indexed draw operation
virtual void DrawIndexed(PipelineHandle pipeline, FramebufferHandle draw_framebuffer,
BufferHandle vertex_buffer, BufferHandle index_buffer, AttribType index_type,
u32 base_index, u32 num_indices, u32 base_vertex) = 0;
virtual void DrawIndexed(PipelineHandle pipeline, FramebufferHandle draw_framebuffer, u32 base_vertex,
u32 base_index, u32 num_indices) = 0;
// Executes a compute shader
virtual void DispatchCompute(PipelineHandle pipeline, Common::Vec3<u32> groupsize,

View File

@@ -46,7 +46,7 @@ static_assert(std::is_standard_layout_v<BufferInfo>, "BufferInfo is not a standa
class BufferBase : public IntrusivePtrEnabled<BufferBase> {
public:
BufferBase() = default;
BufferBase(const BufferInfo& info) : info(info), bind_range(info.capacity) {}
BufferBase(const BufferInfo& info) : info(info) {}
virtual ~BufferBase() = default;
// Disable copy constructor
@@ -61,23 +61,6 @@ public:
// Flushes write to buffer memory
virtual void Commit(u32 size = 0) = 0;
// Sets the range of the buffer that will be used when bound
void SetBindRange(u32 offset, u32 range) {
ASSERT(offset < info.capacity && offset + range < info.capacity);
bind_offset = offset;
bind_range = range;
}
// Returns the bind offset
u32 GetBindOffset() const {
return bind_offset;
}
// Returns the number of bytes after bind_offset that will be bound
u32 GetBindRange() const {
return bind_range;
}
// Returns the size of the buffer in bytes
u32 GetCapacity() const {
return info.capacity;
@@ -89,7 +72,7 @@ public:
}
// Returns the starting offset of the currently mapped buffer slice
u64 GetCurrentOffset() const {
u32 GetCurrentOffset() const {
return buffer_offset;
}
@@ -106,8 +89,6 @@ public:
protected:
BufferInfo info{};
u32 bind_offset = 0;
u32 bind_range; // Initialized to capacity
u32 buffer_offset = 0;
bool invalid = false;
};

View File

@@ -57,17 +57,22 @@ public:
}
// Sets the area of the framebuffer affected by draw operations
void SetDrawRect(Rect2D rect) {
void SetDrawRect(Common::Rectangle<u32> rect) {
draw_rect = rect;
}
// Returns the area of the framebuffer affected by draw operations
Common::Rectangle<u32> GetDrawRect() {
return draw_rect;
}
// Returns how many samples the framebuffer takes
MSAASamples GetMSAASamples() const {
return info.samples;
}
protected:
Rect2D draw_rect;
Common::Rectangle<u32> draw_rect;
FramebufferInfo info;
};

View File

@@ -93,4 +93,14 @@ static_assert(sizeof(VSUniformData) == 1856,
"The size of the VSUniformData structure has changed, update the structure in the shader");
inline Common::Vec4f ColorRGBA8(const u32 color) {
return Common::Vec4f{(color >> 0 & 0xFF), (color >> 8 & 0xFF),
(color >> 16 & 0xFF), (color >> 24 & 0xFF)} / 255.0f;
}
inline Common::Vec3f LightColor(const Pica::LightingRegs::LightColor& color) {
return Common::Vec3f{color.r, color.g, color.b} / 255.0f;
}
} // namespace VideoCore

View File

@@ -17,7 +17,8 @@
namespace VideoCore {
constexpr u32 MAX_SHADER_STAGES = 3;
constexpr u32 MAX_VERTEX_ATTRIBUTES = 8;
constexpr u32 MAX_VERTEX_ATTRIBUTES = 16;
constexpr u32 MAX_VERTEX_BINDINGS = 16;
constexpr u32 MAX_BINDINGS_IN_GROUP = 7;
constexpr u32 MAX_BINDING_GROUPS = 6;
@@ -74,16 +75,18 @@ union DepthStencilState {
union BlendState {
u32 value = 0;
BitField<0, 4, Pica::BlendFactor> src_color_blend_factor;
BitField<4, 4, Pica::BlendFactor> dst_color_blend_factor;
BitField<8, 3, Pica::BlendEquation> color_blend_eq;
BitField<11, 4, Pica::BlendFactor> src_alpha_blend_factor;
BitField<15, 4, Pica::BlendFactor> dst_alpha_blend_factor;
BitField<19, 3, Pica::BlendEquation> alpha_blend_eq;
BitField<22, 4, u32> color_write_mask;
BitField<0, 1, u32> blend_enable;
BitField<1, 4, Pica::BlendFactor> src_color_blend_factor;
BitField<5, 4, Pica::BlendFactor> dst_color_blend_factor;
BitField<9, 3, Pica::BlendEquation> color_blend_eq;
BitField<12, 4, Pica::BlendFactor> src_alpha_blend_factor;
BitField<16, 4, Pica::BlendFactor> dst_alpha_blend_factor;
BitField<20, 3, Pica::BlendEquation> alpha_blend_eq;
BitField<23, 4, u32> color_write_mask;
BitField<27, 4, Pica::LogicOp> logic_op;
};
enum class AttribType : u8 {
enum class AttribType : u32 {
Float = 0,
Int = 1,
Short = 2,
@@ -91,14 +94,25 @@ enum class AttribType : u8 {
Ubyte = 4
};
union VertexBinding {
BitField<0, 4, u16> binding;
BitField<4, 1, u16> fixed;
BitField<5, 11, u16> stride;
};
union VertexAttribute {
BitField<0, 3, AttribType> type;
BitField<3, 3, u8> components;
BitField<0, 4, u32> binding;
BitField<4, 4, u32> location;
BitField<8, 3, AttribType> type;
BitField<11, 3, u32> size;
BitField<14, 11, u32> offset;
};
#pragma pack(1)
struct VertexLayout {
u8 stride = 0;
u8 binding_count = 0;
u8 attribute_count = 0;
std::array<VertexBinding, MAX_VERTEX_BINDINGS> bindings{};
std::array<VertexAttribute, MAX_VERTEX_ATTRIBUTES> attributes{};
};
#pragma pack()
@@ -123,11 +137,12 @@ struct PipelineInfo {
};
#pragma pack()
constexpr s32 WHOLE_SIZE = -1;
// An opaque handle to a backend specific program pipeline
class PipelineBase : public IntrusivePtrEnabled<PipelineBase> {
public:
PipelineBase(PipelineType type, PipelineInfo info) :
type(type), info(info) {}
PipelineBase(PipelineType type, PipelineInfo info) : info(info), type(type) {}
virtual ~PipelineBase() = default;
// Disable copy constructor
@@ -138,83 +153,26 @@ public:
virtual void BindTexture(u32 group, u32 slot, TextureHandle handle) = 0;
// Binds the texture in the specified slot
virtual void BindBuffer(u32 group, u32 slot, BufferHandle handle, u32 view = 0) = 0;
virtual void BindBuffer(u32 group, u32 slot, BufferHandle handle,
u32 offset = 0, u32 range = WHOLE_SIZE, u32 view = 0) = 0;
// Binds the sampler in the specified slot
virtual void BindSampler(u32 group, u32 slot, SamplerHandle handle) = 0;
// Sets the viewport of the pipeline
virtual void SetViewport(Rect2D viewport) = 0;
// Sets the scissor of the pipeline
virtual void SetScissor(Rect2D scissor) = 0;
// Returns the pipeline type (Graphics or Compute)
PipelineType GetType() const {
return type;
}
/// Sets the primitive topology
void SetTopology(Pica::TriangleTopology topology) {
info.rasterization.topology.Assign(topology);
}
/// Sets the culling mode
void SetCullMode(Pica::CullMode mode) {
info.rasterization.cull_mode.Assign(mode);
}
/// Configures the color blending function
void SetColorBlendFunc(Pica::BlendFactor src_color_factor,
Pica::BlendFactor dst_color_factor,
Pica::BlendEquation color_eq) {
info.blending.src_color_blend_factor.Assign(src_color_factor);
info.blending.dst_color_blend_factor.Assign(dst_color_factor);
info.blending.color_blend_eq.Assign(color_eq);
}
/// Configures the alpha blending function
void SetAlphaBlendFunc(Pica::BlendFactor src_alpha_factor,
Pica::BlendFactor dst_alpha_factor,
Pica::BlendEquation alpha_eq) {
info.blending.src_alpha_blend_factor.Assign(src_alpha_factor);
info.blending.dst_alpha_blend_factor.Assign(dst_alpha_factor);
info.blending.alpha_blend_eq.Assign(alpha_eq);
}
/// Sets the color write mask
void SetColorWriteMask(u32 mask) {
info.blending.color_write_mask.Assign(mask);
}
/// Configures the depth test
void SetDepthTest(bool enable, Pica::CompareFunc compare_op) {
info.depth_stencil.depth_test_enable.Assign(enable);
info.depth_stencil.depth_compare_op.Assign(compare_op);
}
/// Enables or disables depth writes
void SetDepthWrites(bool enable) {
info.depth_stencil.depth_write_enable.Assign(enable);
}
/// Configures the stencil test
void SetStencilTest(bool enable, Pica::StencilAction fail, Pica::StencilAction pass,
Pica::StencilAction depth_fail, Pica::CompareFunc compare, u32 ref) {
info.depth_stencil.stencil_test_enable.Assign(enable);
info.depth_stencil.stencil_fail_op.Assign(fail);
info.depth_stencil.stencil_pass_op.Assign(pass);
info.depth_stencil.stencil_depth_fail_op.Assign(depth_fail);
info.depth_stencil.stencil_compare_op.Assign(compare);
info.depth_stencil.stencil_reference.Assign(ref);
}
/// Selects the bits of the stencil values participating in the stencil test
void SetStencilCompareMask(u32 mask) {
info.depth_stencil.stencil_compare_mask.Assign(mask);
}
/// Selects the bits of the stencil values updated by the stencil test
void SetStencilWriteMask(u32 mask) {
info.depth_stencil.stencil_write_mask.Assign(mask);
}
protected:
PipelineInfo info;
PipelineType type = PipelineType::Graphics;
PipelineInfo info{};
};
using PipelineHandle = IntrusivePtr<PipelineBase>;

View File

@@ -44,6 +44,22 @@ PipelineCache::PipelineCache(Frontend::EmuWindow& emu_window, std::unique_ptr<Ba
//generator = std::make_unique<ShaderGenerator
}
PipelineHandle PipelineCache::GetPipeline(PipelineInfo& info) {
// Update shader handles
info.shaders[static_cast<u32>(ProgramType::VertexShader)] = current_vertex_shader;
info.shaders[static_cast<u32>(ProgramType::GeometryShader)] = current_geometry_shader;
info.shaders[static_cast<u32>(ProgramType::FragmentShader)] = current_fragment_shader;
// Search cache
if (auto iter = cached_pipelines.find(info); iter != cached_pipelines.end()) {
return iter->second;
}
// Create new pipeline
auto iter = cached_pipelines.emplace(info, backend->CreatePipeline(PipelineType::Graphics, info)).first;
return iter->second;
}
bool PipelineCache::UsePicaVertexShader(const Pica::Regs& regs, Pica::Shader::ShaderSetup& setup) {
PicaVSConfig config{regs.vs, setup};
auto [handle, shader_str] = pica_vertex_shaders.Get(config, setup);

View File

@@ -38,6 +38,9 @@ public:
PipelineCache(Frontend::EmuWindow& emu_window, std::unique_ptr<BackendBase>& backend);
~PipelineCache() = default;
// Searches the cache for pipelines matching the information structure
PipelineHandle GetPipeline(PipelineInfo& info);
// Loads backend specific shader binaries from disk
void LoadDiskCache(const std::atomic_bool& stop_loading, const DiskLoadCallback& callback);

File diff suppressed because it is too large Load Diff

View File

@@ -4,29 +4,27 @@
#pragma once
#include <array>
#include <vector>
#include <memory>
#include "common/vector_math.h"
#include "video_core/regs_lighting.h"
#include "video_core/regs_texturing.h"
#include "video_core/common/rasterizer_cache.h"
#include "video_core/common/pica_uniforms.h"
#include "video_core/common/pipeline.h"
#include "video_core/shader/shader.h"
namespace Frontend {
class EmuWindow;
}
namespace VideoCore {
class ShaderProgramManager;
class PipelineCache;
/// Structure that the hardware rendered vertices are composed of
class Callback;
using DiskLoadCallback = Callback;
// Structure that the hardware rendered vertices are composed of
struct HardwareVertex {
HardwareVertex() = default;
HardwareVertex(const Pica::Shader::OutputVertex& v, bool flip_quaternion);
// Returns the pipeline vertex layout of the vertex
// Returns the pipeline vertex layout of the vertex used with software shaders
constexpr static VertexLayout GetVertexLayout();
Common::Vec4f position;
@@ -46,8 +44,7 @@ public:
explicit Rasterizer(Frontend::EmuWindow& emu_window, std::unique_ptr<BackendBase>& backend);
~Rasterizer();
//void LoadDiskResources(const std::atomic_bool& stop_loading,
// const VideoCore::DiskResourceLoadCallback& callback);
void LoadDiskResources(const std::atomic_bool& stop_loading, const DiskLoadCallback& callback);
void AddTriangle(const Pica::Shader::OutputVertex& v0, const Pica::Shader::OutputVertex& v1,
const Pica::Shader::OutputVertex& v2);
@@ -58,6 +55,7 @@ public:
void InvalidateRegion(PAddr addr, u32 size);
void FlushAndInvalidateRegion(PAddr addr, u32 size);
void ClearAll(bool flush);
bool AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config);
bool AccelerateTextureCopy(const GPU::Regs::DisplayTransferConfig& config);
bool AccelerateFill(const GPU::Regs::MemoryFillConfig& config);
@@ -170,13 +168,13 @@ private:
void SyncAndUploadLUTsLF();
/// Upload the uniform blocks to the uniform buffer object
void UploadUniforms(bool accelerate_draw);
void UploadUniforms(PipelineHandle pipeline, bool accelerate_draw);
/// Generic draw function for DrawTriangles and AccelerateDrawBatch
bool Draw(bool accelerate, bool is_indexed);
/// Internal implementation for AccelerateDrawBatch
bool AccelerateDrawBatchInternal(bool is_indexed);
bool AccelerateDrawBatchInternal(PipelineHandle pipeline, FramebufferHandle framebuffer, bool is_indexed);
struct VertexArrayInfo {
u32 vs_input_index_min;
@@ -188,7 +186,7 @@ private:
VertexArrayInfo AnalyzeVertexArray(bool is_indexed);
/// Setup vertex array for AccelerateDrawBatch
void SetupVertexArray(u8* array_ptr, u32 buffer_offset, u32 vs_input_index_min, u32 vs_input_index_max);
void SetupVertexArray(u32 vs_input_size, u32 vs_input_index_min, u32 vs_input_index_max);
private:
std::unique_ptr<BackendBase>& backend;
@@ -209,13 +207,17 @@ private:
bool dirty = true;
} uniform_block_data{};
std::unique_ptr<ShaderProgramManager> shader_program_manager;
// Pipeline information structure used to identify a rasterizer pipeline
// The shader handles are automatically filled by the pipeline cache
PipelineInfo raster_info{};
std::unique_ptr<PipelineCache> pipeline_cache;
// Clear texture for placeholder purposes
TextureHandle clear_texture;
// Uniform alignment
std::array<bool, 16> hw_vao_enabled_attributes{};
std::size_t uniform_buffer_alignment;
std::size_t uniform_size_aligned_vs = 0;
std::size_t uniform_size_aligned_fs = 0;
@@ -229,8 +231,8 @@ private:
std::array<Common::Vec2f, 128> proctex_noise_lut_data{};
std::array<Common::Vec2f, 128> proctex_color_map_data{};
std::array<Common::Vec2f, 128> proctex_alpha_map_data{};
std::array<Common::Vec2f, 256> proctex_lut_data{};
std::array<Common::Vec2f, 256> proctex_diff_lut_data{};
std::array<Common::Vec4f, 256> proctex_lut_data{};
std::array<Common::Vec4f, 256> proctex_diff_lut_data{};
// Texture unit sampler cache
SamplerInfo texture_cube_sampler;

View File

@@ -1166,8 +1166,8 @@ const CachedTextureCube& RasterizerCache::GetTextureCube(const TextureCubeConfig
return cube;
}
FramebufferHandle RasterizerCache::GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb,
Common::Rectangle<s32> viewport_rect) {
SurfaceSurfaceRect_Tuple RasterizerCache::GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb,
Common::Rectangle<s32> viewport_rect) {
const auto& config = Pica::g_state.regs.framebuffer.framebuffer;
// update resolution_scale_factor and reset cache if changed
@@ -1256,9 +1256,13 @@ FramebufferHandle RasterizerCache::GetFramebufferSurfaces(bool using_color_fb, b
depth_surface->InvalidateAllWatcher();
}
return std::make_tuple(color_surface, depth_surface, fb_rect);
}
FramebufferHandle RasterizerCache::GetFramebuffer(const Surface& color, const Surface& depth_stencil) {
const FramebufferInfo framebuffer_info = {
.color = using_color_fb ? color_surface->texture : TextureHandle{},
.depth_stencil = using_depth_fb ? depth_surface->texture : TextureHandle{}
.color = color ? color->texture : TextureHandle{},
.depth_stencil = depth_stencil ? depth_stencil->texture : TextureHandle{}
};
// Search the framebuffer cache, otherwise create new framebuffer
@@ -1270,7 +1274,6 @@ FramebufferHandle RasterizerCache::GetFramebufferSurfaces(bool using_color_fb, b
framebuffer_cache.emplace(framebuffer_info, framebuffer);
}
framebuffer->SetDrawRect(fb_rect);
return framebuffer;
}

View File

@@ -4,14 +4,11 @@
#pragma once
#include <array>
#include <memory>
#include <tuple>
#include <boost/icl/interval_map.hpp>
#include <boost/icl/interval_set.hpp>
#include <boost/functional/hash.hpp>
#include "common/assert.h"
#include "common/math_util.h"
#include "core/custom_tex_cache.h"
#include "video_core/common/surface_params.h"
#include "video_core/common/texture.h"
@@ -233,9 +230,12 @@ public:
const CachedTextureCube& GetTextureCube(const TextureCubeConfig& config);
// Get the color and depth surfaces based on the framebuffer configuration
FramebufferHandle GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb,
SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb,
Common::Rectangle<s32> viewport_rect);
// Get the framebuffer for the provided color and depth surfaces
FramebufferHandle GetFramebuffer(const Surface& color, const Surface& depth_stencil);
// Get a surface that matches the fill config
Surface GetFillSurface(const GPU::Regs::MemoryFillConfig& config);

View File

@@ -112,6 +112,9 @@ public:
u32 src_level = 0, u32 dest_level = 0,
u32 src_layer = 0, u32 dest_layer = 0) {};
// Copies texture data from the source texture
virtual void CopyFrom(TextureHandle source) {};
// Generates all possible mipmaps from the texture
virtual void GenerateMipmaps() {};

View File

@@ -161,6 +161,7 @@ struct FramebufferRegs {
} stencil_test;
union {
u32 depth_color_mask;
BitField<0, 1, u32> depth_test_enable;
BitField<4, 3, CompareFunc> depth_test_func;
BitField<8, 1, u32> red_enable;

View File

@@ -84,9 +84,17 @@ struct PipelineRegs {
}
u32 GetElementSizeInBytes(std::size_t n) const {
return (GetFormat(n) == VertexAttributeFormat::FLOAT)
? 4
: (GetFormat(n) == VertexAttributeFormat::SHORT) ? 2 : 1;
switch (GetFormat(n)) {
case VertexAttributeFormat::FLOAT:
return 4;
case VertexAttributeFormat::SHORT:
return 2;
case VertexAttributeFormat::BYTE:
case VertexAttributeFormat::UBYTE:
return 1;
default:
LOG_ERROR(HW_GPU, "Unknown vertex attribute format {}!", GetFormat(n));
}
}
u32 GetStride(std::size_t n) const {

View File

@@ -67,6 +67,9 @@ u32 AttribBytes(VertexAttribute attrib) {
return sizeof(u32) * attrib.components;
case AttribType::Short:
return sizeof(u16) * attrib.components;
case AttribType::Byte:
case AttribType::Ubyte:
return sizeof(u8) * attrib.components;
}
}
@@ -208,6 +211,12 @@ Pipeline::Pipeline(Instance& instance, PipelineLayout& owner, PipelineType type,
// Create a graphics pipeline
if (type == PipelineType::Graphics) {
/**
* Most modern graphics APIs don't natively support constant attributes. To avoid duplicating
* the data and increasing data bandwith, we reserve the last binding for fixed attributes,
* which are always interleaved and specify VK_VERTEX_INPUT_RATE_INSTANCE as the input rate.
* Since we are always rendering 1 instance, the shader will always read the single attribute
*/
const vk::VertexInputBindingDescription binding_desc = {
.binding = 0,
.stride = info.vertex_layout.stride