2018-03-20 01:55:14 +01:00
|
|
|
// Copyright 2018 yuzu Emulator Project
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2018-04-07 10:51:42 +02:00
|
|
|
#include <array>
|
2018-03-20 01:55:14 +01:00
|
|
|
#include <string>
|
2018-04-15 09:32:12 +02:00
|
|
|
#include <vector>
|
2018-08-23 23:30:27 +02:00
|
|
|
|
2018-04-07 10:51:42 +02:00
|
|
|
#include "common/common_types.h"
|
2018-09-07 00:45:49 +02:00
|
|
|
#include "video_core/engines/shader_bytecode.h"
|
2018-03-20 01:55:14 +01:00
|
|
|
|
2018-08-21 10:18:27 +02:00
|
|
|
namespace OpenGL::GLShader {
|
2018-03-20 01:55:14 +01:00
|
|
|
|
2018-09-15 15:21:06 +02:00
|
|
|
constexpr std::size_t MAX_PROGRAM_CODE_LENGTH{0x1000};
|
2018-08-22 21:43:52 +02:00
|
|
|
using ProgramCode = std::vector<u64>;
|
2018-04-07 10:51:42 +02:00
|
|
|
|
2018-04-15 09:32:12 +02:00
|
|
|
class ConstBufferEntry {
|
2018-04-15 21:42:23 +02:00
|
|
|
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
|
|
|
|
2018-04-15 09:32:12 +02:00
|
|
|
public:
|
2018-06-06 05:34:37 +02:00
|
|
|
void MarkAsUsed(u64 index, u64 offset, Maxwell::ShaderStage stage) {
|
2018-04-15 09:32:12 +02:00
|
|
|
is_used = true;
|
2018-06-06 05:34:37 +02:00
|
|
|
this->index = static_cast<unsigned>(index);
|
|
|
|
this->stage = stage;
|
|
|
|
max_offset = std::max(max_offset, static_cast<unsigned>(offset));
|
|
|
|
}
|
|
|
|
|
|
|
|
void MarkAsUsedIndirect(u64 index, Maxwell::ShaderStage stage) {
|
|
|
|
is_used = true;
|
|
|
|
is_indirect = true;
|
|
|
|
this->index = static_cast<unsigned>(index);
|
2018-04-15 21:42:23 +02:00
|
|
|
this->stage = stage;
|
2018-04-15 09:32:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool IsUsed() const {
|
|
|
|
return is_used;
|
|
|
|
}
|
|
|
|
|
2018-06-06 05:34:37 +02:00
|
|
|
bool IsIndirect() const {
|
|
|
|
return is_indirect;
|
|
|
|
}
|
|
|
|
|
2018-04-15 09:32:12 +02:00
|
|
|
unsigned GetIndex() const {
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned GetSize() const {
|
|
|
|
return max_offset + 1;
|
|
|
|
}
|
|
|
|
|
2018-04-15 21:42:23 +02:00
|
|
|
std::string GetName() const {
|
2018-09-15 15:21:06 +02:00
|
|
|
return BufferBaseNames[static_cast<std::size_t>(stage)] + std::to_string(index);
|
2018-04-15 21:42:23 +02:00
|
|
|
}
|
|
|
|
|
2018-09-04 20:55:34 +02:00
|
|
|
u32 GetHash() const {
|
|
|
|
return (static_cast<u32>(stage) << 16) | index;
|
|
|
|
}
|
|
|
|
|
2018-04-15 09:32:12 +02:00
|
|
|
private:
|
2018-04-15 21:42:23 +02:00
|
|
|
static constexpr std::array<const char*, Maxwell::MaxShaderStage> BufferBaseNames = {
|
|
|
|
"buffer_vs_c", "buffer_tessc_c", "buffer_tesse_c", "buffer_gs_c", "buffer_fs_c",
|
|
|
|
};
|
|
|
|
|
2018-04-15 09:32:12 +02:00
|
|
|
bool is_used{};
|
2018-06-06 05:34:37 +02:00
|
|
|
bool is_indirect{};
|
2018-04-15 09:32:12 +02:00
|
|
|
unsigned index{};
|
|
|
|
unsigned max_offset{};
|
2018-04-15 21:42:23 +02:00
|
|
|
Maxwell::ShaderStage stage;
|
2018-04-15 09:32:12 +02:00
|
|
|
};
|
|
|
|
|
2018-06-06 19:58:16 +02:00
|
|
|
class SamplerEntry {
|
|
|
|
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
|
|
|
|
|
|
|
public:
|
2018-09-15 15:21:06 +02:00
|
|
|
SamplerEntry(Maxwell::ShaderStage stage, std::size_t offset, std::size_t index,
|
2018-09-07 00:45:49 +02:00
|
|
|
Tegra::Shader::TextureType type, bool is_array)
|
|
|
|
: offset(offset), stage(stage), sampler_index(index), type(type), is_array(is_array) {}
|
2018-06-06 19:58:16 +02:00
|
|
|
|
2018-09-15 15:21:06 +02:00
|
|
|
std::size_t GetOffset() const {
|
2018-06-06 19:58:16 +02:00
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
2018-09-15 15:21:06 +02:00
|
|
|
std::size_t GetIndex() const {
|
2018-06-06 19:58:16 +02:00
|
|
|
return sampler_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
Maxwell::ShaderStage GetStage() const {
|
|
|
|
return stage;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string GetName() const {
|
2018-09-15 15:21:06 +02:00
|
|
|
return std::string(TextureSamplerNames[static_cast<std::size_t>(stage)]) + '_' +
|
2018-09-07 00:45:49 +02:00
|
|
|
std::to_string(sampler_index);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string GetTypeString() const {
|
|
|
|
using Tegra::Shader::TextureType;
|
|
|
|
std::string glsl_type;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case TextureType::Texture1D:
|
|
|
|
glsl_type = "sampler1D";
|
|
|
|
break;
|
|
|
|
case TextureType::Texture2D:
|
|
|
|
glsl_type = "sampler2D";
|
|
|
|
break;
|
|
|
|
case TextureType::Texture3D:
|
|
|
|
glsl_type = "sampler3D";
|
|
|
|
break;
|
|
|
|
case TextureType::TextureCube:
|
|
|
|
glsl_type = "samplerCube";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
if (is_array)
|
|
|
|
glsl_type += "Array";
|
|
|
|
return glsl_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
Tegra::Shader::TextureType GetType() const {
|
|
|
|
return type;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsArray() const {
|
|
|
|
return is_array;
|
2018-06-06 19:58:16 +02:00
|
|
|
}
|
|
|
|
|
2018-09-04 20:55:34 +02:00
|
|
|
u32 GetHash() const {
|
|
|
|
return (static_cast<u32>(stage) << 16) | static_cast<u32>(sampler_index);
|
|
|
|
}
|
|
|
|
|
2018-06-06 19:58:16 +02:00
|
|
|
static std::string GetArrayName(Maxwell::ShaderStage stage) {
|
2018-09-15 15:21:06 +02:00
|
|
|
return TextureSamplerNames[static_cast<std::size_t>(stage)];
|
2018-06-06 19:58:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
static constexpr std::array<const char*, Maxwell::MaxShaderStage> TextureSamplerNames = {
|
|
|
|
"tex_vs", "tex_tessc", "tex_tesse", "tex_gs", "tex_fs",
|
|
|
|
};
|
2018-09-07 00:45:49 +02:00
|
|
|
|
2018-06-06 19:58:16 +02:00
|
|
|
/// Offset in TSC memory from which to read the sampler object, as specified by the sampling
|
|
|
|
/// instruction.
|
2018-09-15 15:21:06 +02:00
|
|
|
std::size_t offset;
|
2018-09-07 00:45:49 +02:00
|
|
|
Maxwell::ShaderStage stage; ///< Shader stage where this sampler was used.
|
2018-09-15 15:21:06 +02:00
|
|
|
std::size_t sampler_index; ///< Value used to index into the generated GLSL sampler array.
|
2018-09-07 00:45:49 +02:00
|
|
|
Tegra::Shader::TextureType type; ///< The type used to sample this texture (Texture2D, etc)
|
|
|
|
bool is_array; ///< Whether the texture is being sampled as an array texture or not.
|
2018-06-06 19:58:16 +02:00
|
|
|
};
|
|
|
|
|
2018-04-15 09:32:12 +02:00
|
|
|
struct ShaderEntries {
|
|
|
|
std::vector<ConstBufferEntry> const_buffer_entries;
|
2018-06-06 19:58:16 +02:00
|
|
|
std::vector<SamplerEntry> texture_samplers;
|
2018-04-15 09:32:12 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
using ProgramResult = std::pair<std::string, ShaderEntries>;
|
|
|
|
|
2018-04-07 10:51:42 +02:00
|
|
|
struct ShaderSetup {
|
2018-08-22 23:01:14 +02:00
|
|
|
explicit ShaderSetup(ProgramCode program_code) {
|
2018-08-22 21:43:52 +02:00
|
|
|
program.code = std::move(program_code);
|
2018-07-13 04:25:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
struct {
|
|
|
|
ProgramCode code;
|
|
|
|
ProgramCode code_b; // Used for dual vertex shaders
|
|
|
|
} program;
|
2018-04-07 10:51:42 +02:00
|
|
|
|
2018-07-13 04:25:03 +02:00
|
|
|
/// Used in scenarios where we have a dual vertex shaders
|
2018-08-23 23:30:27 +02:00
|
|
|
void SetProgramB(ProgramCode&& program_b) {
|
2018-08-22 21:43:52 +02:00
|
|
|
program.code_b = std::move(program_b);
|
2018-07-13 04:25:03 +02:00
|
|
|
has_program_b = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool IsDualProgram() const {
|
|
|
|
return has_program_b;
|
|
|
|
}
|
|
|
|
|
2018-04-07 10:51:42 +02:00
|
|
|
private:
|
2018-07-13 04:25:03 +02:00
|
|
|
bool has_program_b{};
|
2018-03-20 01:55:14 +01:00
|
|
|
};
|
|
|
|
|
2018-04-07 10:51:42 +02:00
|
|
|
/**
|
|
|
|
* Generates the GLSL vertex shader program source code for the given VS program
|
|
|
|
* @returns String of the shader source code
|
|
|
|
*/
|
2018-08-23 23:30:27 +02:00
|
|
|
ProgramResult GenerateVertexShader(const ShaderSetup& setup);
|
2018-04-07 10:51:42 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Generates the GLSL fragment shader program source code for the given FS program
|
|
|
|
* @returns String of the shader source code
|
|
|
|
*/
|
2018-08-23 23:30:27 +02:00
|
|
|
ProgramResult GenerateFragmentShader(const ShaderSetup& setup);
|
2018-03-20 01:55:14 +01:00
|
|
|
|
2018-08-21 10:18:27 +02:00
|
|
|
} // namespace OpenGL::GLShader
|