ShaderGen: Implement pixel ubershaders

This commit is contained in:
Stenzek 2017-07-20 15:25:24 +10:00
parent 07591e7d5c
commit 7d78cf0f6f
19 changed files with 1520 additions and 17 deletions

View file

@ -78,6 +78,8 @@ void VideoBackend::InitBackendInfo()
g_Config.backend_info.bSupportsInternalResolutionFrameDumps = false;
g_Config.backend_info.bSupportsGPUTextureDecoding = false;
g_Config.backend_info.bSupportsST3CTextures = false;
g_Config.backend_info.bSupportsBitfield = false;
g_Config.backend_info.bSupportsDynamicSamplerIndexing = false;
IDXGIFactory* factory;
IDXGIAdapter* ad;

View file

@ -447,6 +447,12 @@ Renderer::Renderer()
// Clip distance support is useless without a method to clamp the depth range
g_Config.backend_info.bSupportsDepthClamp = GLExtensions::Supports("GL_ARB_depth_clamp");
// Desktop OpenGL supports bitfield manulipation and dynamic sampler indexing if it supports
// shader5. OpenGL ES 3.1 supports it implicitly without an extension
g_Config.backend_info.bSupportsBitfield = GLExtensions::Supports("GL_ARB_gpu_shader5");
g_Config.backend_info.bSupportsDynamicSamplerIndexing =
GLExtensions::Supports("GL_ARB_gpu_shader5");
g_ogl_config.bSupportsGLSLCache = GLExtensions::Supports("GL_ARB_get_program_binary");
g_ogl_config.bSupportsGLPinnedMemory = GLExtensions::Supports("GL_AMD_pinned_memory");
g_ogl_config.bSupportsGLSync = GLExtensions::Supports("GL_ARB_sync");
@ -515,6 +521,8 @@ Renderer::Renderer()
g_ogl_config.bSupportsMSAA = true;
g_ogl_config.bSupportsTextureStorage = true;
g_ogl_config.bSupports2DTextureStorageMultisample = true;
g_Config.backend_info.bSupportsBitfield = true;
g_Config.backend_info.bSupportsDynamicSamplerIndexing = g_ogl_config.bSupportsAEP;
if (g_ActiveConfig.iStereoMode > 0 && g_ActiveConfig.iMultisamples > 1 &&
!g_ogl_config.bSupports3DTextureStorageMultisample)
{
@ -542,6 +550,8 @@ Renderer::Renderer()
g_ogl_config.bSupportsTextureStorage = true;
g_ogl_config.bSupports2DTextureStorageMultisample = true;
g_ogl_config.bSupports3DTextureStorageMultisample = true;
g_Config.backend_info.bSupportsBitfield = true;
g_Config.backend_info.bSupportsDynamicSamplerIndexing = true;
}
}
else

View file

@ -236,6 +236,8 @@ void VulkanContext::PopulateBackendInfo(VideoConfig* config)
config->backend_info.bSupportsMultithreading = true; // Assumed support.
config->backend_info.bSupportsComputeShaders = true; // Assumed support.
config->backend_info.bSupportsGPUTextureDecoding = true; // Assumed support.
config->backend_info.bSupportsBitfield = true; // Assumed support.
config->backend_info.bSupportsDynamicSamplerIndexing = true; // Assumed support.
config->backend_info.bSupportsInternalResolutionFrameDumps = true; // Assumed support.
config->backend_info.bSupportsPostProcessing = true; // Assumed support.
config->backend_info.bSupportsDualSourceBlend = false; // Dependent on features.

View file

@ -93,6 +93,9 @@ static void BPWritten(const BPCmd& bp)
(u32)bpmem.genMode.cullmode, (u32)bpmem.genMode.numindstages,
(u32)bpmem.genMode.zfreeze);
if (bp.changes)
PixelShaderManager::SetGenModeChanged();
// Only call SetGenerationMode when cull mode changes.
if (bp.changes & 0xC000)
SetGenerationMode();
@ -155,13 +158,20 @@ static void BPWritten(const BPCmd& bp)
// Set Color Mask
if (bp.changes & 0x18) // colorupdate | alphaupdate
SetColorMask();
// Dither
if (bp.changes & 0x04)
PixelShaderManager::SetBlendModeChanged();
}
return;
case BPMEM_CONSTANTALPHA: // Set Destination Alpha
PRIM_LOG("constalpha: alp=%d, en=%d", bpmem.dstalpha.alpha.Value(),
bpmem.dstalpha.enable.Value());
if (bp.changes & 0xFF)
PixelShaderManager::SetDestAlpha();
if (bp.changes)
{
PixelShaderManager::SetAlpha();
PixelShaderManager::SetDestAlphaChanged();
}
if (bp.changes & 0x100)
SetBlendMode();
return;
@ -238,6 +248,7 @@ static void BPWritten(const BPCmd& bp)
// the number of lines copied is determined by the y scale * source efb height
BoundingBox::active = false;
PixelShaderManager::SetBoundingBoxActive(false);
float yScale;
if (PE_copy.scale_invert)
@ -318,6 +329,7 @@ static void BPWritten(const BPCmd& bp)
PixelShaderManager::SetAlpha();
if (bp.changes)
{
PixelShaderManager::SetAlphaTestChanged();
g_renderer->SetColorMask();
SetBlendMode();
}
@ -332,7 +344,7 @@ static void BPWritten(const BPCmd& bp)
if (bp.changes & 3)
PixelShaderManager::SetZTextureTypeChanged();
if (bp.changes & 12)
VertexShaderManager::SetViewportChanged();
PixelShaderManager::SetZTextureOpChanged();
#if defined(_DEBUG) || defined(DEBUGFAST)
const char* pzop[] = {"DISABLE", "ADD", "REPLACE", "?"};
const char* pztype[] = {"Z8", "Z16", "Z24", "?"};
@ -390,6 +402,7 @@ static void BPWritten(const BPCmd& bp)
{
u8 offset = bp.address & 2;
BoundingBox::active = true;
PixelShaderManager::SetBoundingBoxActive(true);
if (g_ActiveConfig.backend_info.bSupportsBBox && g_ActiveConfig.bBBoxEnable)
{
@ -426,6 +439,11 @@ static void BPWritten(const BPCmd& bp)
* 3 BC0 - Ind. Tex Stage 0 NTexCoord
* 0 BI0 - Ind. Tex Stage 0 NTexMap */
case BPMEM_IREF:
{
if (bp.changes)
PixelShaderManager::SetTevIndirectChanged();
return;
}
case BPMEM_TEV_KSEL: // Texture Environment Swap Mode Table 0
case BPMEM_TEV_KSEL + 1: // Texture Environment Swap Mode Table 1
@ -435,6 +453,8 @@ static void BPWritten(const BPCmd& bp)
case BPMEM_TEV_KSEL + 5: // Texture Environment Swap Mode Table 5
case BPMEM_TEV_KSEL + 6: // Texture Environment Swap Mode Table 6
case BPMEM_TEV_KSEL + 7: // Texture Environment Swap Mode Table 7
PixelShaderManager::SetTevKSel(bp.address - BPMEM_TEV_KSEL, bp.newvalue);
return;
/* This Register can be used to limit to which bits of BP registers is
* actually written to. The mask is only valid for the next BP write,
@ -567,6 +587,7 @@ static void BPWritten(const BPCmd& bp)
// -------------------------
case BPMEM_TREF:
case BPMEM_TREF + 4:
PixelShaderManager::SetTevOrder(bp.address - BPMEM_TREF, bp.newvalue);
return;
// ----------------------
// Set wrap size
@ -630,15 +651,18 @@ static void BPWritten(const BPCmd& bp)
// --------------
// Indirect Tev
// --------------
case BPMEM_IND_CMD: // Indirect 0-15
case BPMEM_IND_CMD:
PixelShaderManager::SetTevIndirectChanged();
return;
// --------------------------------------------------
// Set Color/Alpha of a Tev
// BPMEM_TEV_COLOR_ENV - Dest, Shift, Clamp, Sub, Bias, Sel A, Sel B, Sel C, Sel D
// BPMEM_TEV_ALPHA_ENV - Dest, Shift, Clamp, Sub, Bias, Sel A, Sel B, Sel C, Sel D, T Swap, R Swap
// --------------------------------------------------
case BPMEM_TEV_COLOR_ENV: // Texture Environment Color/Alpha 0-7
case BPMEM_TEV_COLOR_ENV + 16: // Texture Environment Color/Alpha 8-15
case BPMEM_TEV_COLOR_ENV: // Texture Environment 1
case BPMEM_TEV_COLOR_ENV + 16:
PixelShaderManager::SetTevCombiner((bp.address - BPMEM_TEV_COLOR_ENV) >> 1,
(bp.address - BPMEM_TEV_COLOR_ENV) & 1, bp.newvalue);
return;
default:
break;

View file

@ -32,6 +32,8 @@ set(SRCS
RenderState.cpp
ShaderGenCommon.cpp
Statistics.cpp
UberShaderCommon.cpp
UberShaderPixel.cpp
TextureCacheBase.cpp
TextureConfig.cpp
TextureConversionShader.cpp

View file

@ -24,7 +24,22 @@ struct PixelShaderConstants
int4 fogi;
float4 fogf[2];
float4 zslope;
float4 efbscale;
float efbscale[2];
// Constants from here onwards are only used in ubershaders.
u32 genmode; // .z
u32 alphaTest; // .w
u32 fogParam3; // .x
u32 fogRangeBase; // .y
u32 dstalpha; // .z
u32 ztex_op; // .w
u32 early_ztest; // .x (bool)
u32 rgba6_format; // .y (bool)
u32 dither; // .z (bool)
u32 bounding_box; // .w (bool)
uint4 pack1[16]; // .xy - combiners, .z - tevind, .w - iref
uint4 pack2[8]; // .x - tevorder, .y - tevksel
int4 konst[32]; // .rgba
};
struct VertexShaderConstants

View file

@ -18,6 +18,7 @@
#include "VideoCommon/CommandProcessor.h"
#include "VideoCommon/Fifo.h"
#include "VideoCommon/PixelEngine.h"
#include "VideoCommon/PixelShaderManager.h"
namespace PixelEngine
{
@ -231,6 +232,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
{
mmio->Register(base | (PE_BBOX_LEFT + 2 * i), MMIO::ComplexRead<u16>([i](u32) {
BoundingBox::active = false;
PixelShaderManager::SetBoundingBoxActive(false);
return g_video_backend->Video_GetBoundingBox(i);
}),
MMIO::InvalidWrite<u16>());

View file

@ -394,8 +394,26 @@ void WritePixelShaderCommonHeader(ShaderCode& out, APIType ApiType, bool boundin
"\tint4 " I_FOGI ";\n"
"\tfloat4 " I_FOGF "[2];\n"
"\tfloat4 " I_ZSLOPE ";\n"
"\tfloat4 " I_EFBSCALE ";\n"
"};\n");
"\tfloat2 " I_EFBSCALE ";\n"
"\tuint bpmem_genmode;\n"
"\tuint bpmem_alphaTest;\n"
"\tuint bpmem_fogParam3;\n"
"\tuint bpmem_fogRangeBase;\n"
"\tuint bpmem_dstalpha;\n"
"\tuint bpmem_ztex_op;\n"
"\tbool bpmem_early_ztest;\n"
"\tbool bpmem_rgba6_format;\n"
"\tbool bpmem_dither;\n"
"\tbool bpmem_bounding_box;\n"
"\tuint4 bpmem_pack1[16];\n" // .xy - combiners, .z - tevind
"\tuint4 bpmem_pack2[8];\n" // .x - tevorder, .y - tevksel
"\tint4 konstLookup[32];\n"
"};\n\n");
out.Write("#define bpmem_combiners(i) (bpmem_pack1[(i)].xy)\n"
"#define bpmem_tevind(i) (bpmem_pack1[(i)].z)\n"
"#define bpmem_iref(i) (bpmem_pack1[(i)].w)\n"
"#define bpmem_tevorder(i) (bpmem_pack2[(i)].x)\n"
"#define bpmem_tevksel(i) (bpmem_pack2[(i)].y)\n\n");
if (bounding_box)
{
@ -449,7 +467,7 @@ ShaderCode GeneratePixelShaderCode(APIType ApiType, const ShaderHostConfig& host
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
out.Write("UBO_BINDING(std140, 2) uniform VSBlock {\n");
else
out.Write("cbuffer VSBlock : register(b2) {\n");
out.Write("cbuffer VSBlock : register(b1) {\n");
out.Write(s_shader_uniforms);
out.Write("};\n");

View file

@ -15,6 +15,8 @@
bool PixelShaderManager::s_bFogRangeAdjustChanged;
bool PixelShaderManager::s_bViewPortChanged;
bool PixelShaderManager::s_bIndirectDirty;
bool PixelShaderManager::s_bDestAlphaDirty;
PixelShaderConstants PixelShaderManager::constants;
bool PixelShaderManager::dirty;
@ -40,6 +42,38 @@ void PixelShaderManager::Init()
SetTexCoordChanged(6);
SetTexCoordChanged(7);
// fixed Konstants
for (int component = 0; component < 4; component++)
{
constants.konst[0][component] = 255; // 1
constants.konst[1][component] = 223; // 7/8
constants.konst[2][component] = 191; // 3/4
constants.konst[3][component] = 159; // 5/8
constants.konst[4][component] = 128; // 1/2
constants.konst[5][component] = 96; // 3/8
constants.konst[6][component] = 64; // 1/4
constants.konst[7][component] = 32; // 1/8
// Invalid Konstants (reads as zero on hardware)
constants.konst[8][component] = 0;
constants.konst[9][component] = 0;
constants.konst[10][component] = 0;
constants.konst[11][component] = 0;
// Annoyingly, alpha reads zero values for the .rgb colors (offically
// defined as invalid)
// If it wasn't for this, we could just use one of the first 3 colunms
// instead of
// wasting an entire 4th column just for alpha.
if (component == 3)
{
constants.konst[12][component] = 0;
constants.konst[13][component] = 0;
constants.konst[14][component] = 0;
constants.konst[15][component] = 0;
}
}
dirty = true;
}
@ -99,6 +133,59 @@ void PixelShaderManager::SetConstants()
dirty = true;
s_bViewPortChanged = false;
}
if (s_bIndirectDirty)
{
for (int i = 0; i < 4; i++)
constants.pack1[i][3] = 0;
for (u32 i = 0; i < (bpmem.genMode.numtevstages + 1); ++i)
{
u32 stage = bpmem.tevind[i].bt;
if (stage < bpmem.genMode.numindstages)
{
// We set some extra bits so the ubershader can quickly check if these
// features are in use.
if (bpmem.tevind[i].IsActive())
constants.pack1[stage][3] =
bpmem.tevindref.getTexCoord(stage) | bpmem.tevindref.getTexMap(stage) << 8 | 1 << 16;
// Note: a tevind of zero just happens to be a passthrough, so no need
// to set an extra bit.
constants.pack1[i][2] =
bpmem.tevind[i].hex; // TODO: This match shadergen, but videosw will
// always wrap.
// The ubershader uses tevind != 0 as a condition whether to calculate texcoords,
// even when texture is disabled, instead of the stage < bpmem.genMode.numindstages.
// We set an unused bit here to indicate that the stage is active, even if it
// is just a pass-through.
constants.pack1[i][2] |= 0x80000000;
}
else
{
constants.pack1[i][2] = 0;
}
}
dirty = true;
s_bIndirectDirty = false;
}
if (s_bDestAlphaDirty)
{
// Destination alpha is only enabled if alpha writes are enabled. Force entire uniform to zero
// when disabled.
u32 dstalpha = bpmem.blendmode.alphaupdate && bpmem.dstalpha.enable &&
bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24 ?
bpmem.dstalpha.hex :
0;
if (constants.dstalpha != dstalpha)
{
constants.dstalpha = dstalpha;
dirty = true;
}
}
}
void PixelShaderManager::SetTevColor(int index, int component, s32 value)
@ -116,20 +203,78 @@ void PixelShaderManager::SetTevKonstColor(int index, int component, s32 value)
c[component] = value;
dirty = true;
// Konst for ubershaders. We build the whole array on cpu so the gpu can do a single indirect
// access.
if (component != 3) // Alpha doesn't included in the .rgb konsts
constants.konst[index + 12][component] = value;
// .rrrr .gggg .bbbb .aaaa konsts
constants.konst[index + 16 + component * 4][0] = value;
constants.konst[index + 16 + component * 4][1] = value;
constants.konst[index + 16 + component * 4][2] = value;
constants.konst[index + 16 + component * 4][3] = value;
PRIM_LOG("tev konst color%d: %d %d %d %d", index, c[0], c[1], c[2], c[3]);
}
void PixelShaderManager::SetTevOrder(int index, u32 order)
{
if (constants.pack2[index][0] != order)
{
constants.pack2[index][0] = order;
dirty = true;
}
}
void PixelShaderManager::SetTevKSel(int index, u32 ksel)
{
if (constants.pack2[index][1] != ksel)
{
constants.pack2[index][1] = ksel;
dirty = true;
}
}
void PixelShaderManager::SetTevCombiner(int index, int alpha, u32 combiner)
{
if (constants.pack1[index][alpha] != combiner)
{
constants.pack1[index][alpha] = combiner;
dirty = true;
}
}
void PixelShaderManager::SetTevIndirectChanged()
{
s_bIndirectDirty = true;
}
void PixelShaderManager::SetAlpha()
{
constants.alpha[0] = bpmem.alpha_test.ref0;
constants.alpha[1] = bpmem.alpha_test.ref1;
constants.alpha[3] = static_cast<s32>(bpmem.dstalpha.alpha);
dirty = true;
}
void PixelShaderManager::SetDestAlpha()
void PixelShaderManager::SetAlphaTestChanged()
{
constants.alpha[3] = bpmem.dstalpha.alpha;
dirty = true;
// Force alphaTest Uniform to zero if it will always pass.
// (set an extra bit to distinguish from "never && never")
// TODO: we could optimize this further and check the actual constants,
// i.e. "a <= 0" and "a >= 255" will always pass.
u32 alpha_test =
bpmem.alpha_test.TestResult() != AlphaTest::PASS ? bpmem.alpha_test.hex | 1 << 31 : 0;
if (constants.alphaTest != alpha_test)
{
constants.alphaTest = alpha_test;
dirty = true;
}
}
void PixelShaderManager::SetDestAlphaChanged()
{
s_bDestAlphaDirty = true;
}
void PixelShaderManager::SetTexDims(int texmapid, u32 width, u32 height)
@ -235,6 +380,12 @@ void PixelShaderManager::SetZTextureTypeChanged()
dirty = true;
}
void PixelShaderManager::SetZTextureOpChanged()
{
constants.ztex_op = bpmem.ztex2.op;
dirty = true;
}
void PixelShaderManager::SetTexCoordChanged(u8 texmapid)
{
TCoordInfo& tc = bpmem.texcoords[texmapid];
@ -262,6 +413,7 @@ void PixelShaderManager::SetFogParamChanged()
constants.fogi[1] = bpmem.fog.b_magnitude;
constants.fogf[1][2] = bpmem.fog.c_proj_fsel.GetC();
constants.fogi[3] = bpmem.fog.b_shift;
constants.fogParam3 = bpmem.fog.c_proj_fsel.hex;
}
else
{
@ -269,6 +421,7 @@ void PixelShaderManager::SetFogParamChanged()
constants.fogi[1] = 1;
constants.fogf[1][2] = 0.f;
constants.fogi[3] = 1;
constants.fogParam3 = 0;
}
dirty = true;
}
@ -279,12 +432,68 @@ void PixelShaderManager::SetFogRangeAdjustChanged()
return;
s_bFogRangeAdjustChanged = true;
if (constants.fogRangeBase != bpmem.fogRange.Base.hex)
{
constants.fogRangeBase = bpmem.fogRange.Base.hex;
dirty = true;
}
}
void PixelShaderManager::SetGenModeChanged()
{
constants.genmode = bpmem.genMode.hex;
s_bIndirectDirty = true;
dirty = true;
}
void PixelShaderManager::SetZControlChanged()
{
u32 early_ztest = bpmem.zcontrol.early_ztest ? 1 : 0;
u32 rgba6_format =
(bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24 && !g_ActiveConfig.bForceTrueColor) ? 1 :
0;
u32 dither = rgba6_format && bpmem.blendmode.dither;
if (constants.early_ztest != early_ztest || constants.rgba6_format != rgba6_format ||
constants.dither != dither)
{
constants.early_ztest = early_ztest;
constants.rgba6_format = rgba6_format;
constants.dither = dither;
dirty = true;
}
s_bDestAlphaDirty = true;
}
void PixelShaderManager::SetBlendModeChanged()
{
u32 dither = constants.rgba6_format && bpmem.blendmode.dither;
if (constants.dither != dither)
{
constants.dither = dither;
dirty = true;
}
s_bDestAlphaDirty = true;
}
void PixelShaderManager::SetBoundingBoxActive(bool active)
{
const bool enable =
active && g_ActiveConfig.bBBoxEnable && g_ActiveConfig.BBoxUseFragmentShaderImplementation();
if (enable == (constants.bounding_box != 0))
return;
constants.bounding_box = active;
dirty = true;
}
void PixelShaderManager::DoState(PointerWrap& p)
{
p.Do(s_bFogRangeAdjustChanged);
p.Do(s_bViewPortChanged);
p.Do(s_bIndirectDirty);
p.Do(s_bDestAlphaDirty);
p.Do(constants);

View file

@ -24,24 +24,36 @@ public:
// so make sure to call them after memory is committed
static void SetTevColor(int index, int component, s32 value);
static void SetTevKonstColor(int index, int component, s32 value);
static void SetTevOrder(int index, u32 order);
static void SetTevKSel(int index, u32 ksel);
static void SetTevCombiner(int index, int alpha, u32 combiner);
static void SetAlpha();
static void SetDestAlpha();
static void SetAlphaTestChanged();
static void SetDestAlphaChanged();
static void SetTexDims(int texmapid, u32 width, u32 height);
static void SetZTextureBias();
static void SetViewportChanged();
static void SetEfbScaleChanged(float scalex, float scaley);
static void SetZSlope(float dfdx, float dfdy, float f0);
static void SetIndMatrixChanged(int matrixidx);
static void SetTevIndirectChanged();
static void SetZTextureTypeChanged();
static void SetZTextureOpChanged();
static void SetIndTexScaleChanged(bool high);
static void SetTexCoordChanged(u8 texmapid);
static void SetFogColorChanged();
static void SetFogParamChanged();
static void SetFogRangeAdjustChanged();
static void SetGenModeChanged();
static void SetZControlChanged();
static void SetBlendModeChanged();
static void SetBoundingBoxActive(bool active);
static PixelShaderConstants constants;
static bool dirty;
static bool s_bFogRangeAdjustChanged;
static bool s_bViewPortChanged;
static bool s_bIndirectDirty;
static bool s_bDestAlphaDirty;
};

View file

@ -29,6 +29,9 @@ ShaderHostConfig ShaderHostConfig::GetCurrent()
bits.backend_atomics = g_ActiveConfig.backend_info.bSupportsFragmentStoresAndAtomics;
bits.backend_depth_clamp = g_ActiveConfig.backend_info.bSupportsDepthClamp;
bits.backend_reversed_depth_range = g_ActiveConfig.backend_info.bSupportsReversedDepthRange;
bits.backend_bitfield = g_ActiveConfig.backend_info.bSupportsBitfield;
bits.backend_dynamic_sampler_indexing =
g_ActiveConfig.backend_info.bSupportsDynamicSamplerIndexing;
return bits;
}
@ -65,7 +68,7 @@ std::string GetDiskShaderCacheFileName(APIType api_type, const char* type, bool
if (include_host_config)
{
// We're using 18 bits, so 5 hex characters.
// We're using 20 bits, so 5 hex characters.
ShaderHostConfig host_config = ShaderHostConfig::GetCurrent();
filename += StringFromFormat("-%05X", host_config.bits);
}

View file

@ -176,7 +176,9 @@ union ShaderHostConfig
u32 backend_atomics : 1;
u32 backend_depth_clamp : 1;
u32 backend_reversed_depth_range : 1;
u32 pad : 14;
u32 backend_bitfield : 1;
u32 backend_dynamic_sampler_indexing : 1;
u32 pad : 12;
};
static ShaderHostConfig GetCurrent();

View file

@ -0,0 +1,27 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "VideoCommon/UberShaderCommon.h"
#include "VideoCommon/VideoConfig.h"
namespace UberShader
{
void WriteUberShaderCommonHeader(ShaderCode& out, APIType api_type,
const ShaderHostConfig& host_config)
{
// ==============================================
// BitfieldExtract for APIs which don't have it
// ==============================================
if (!host_config.backend_bitfield)
{
out.Write("uint bitfieldExtract(uint val, int off, int size) {\n"
" // This built-in function is only support in OpenGL 4.0+ and ES 3.1+\n"
" // Microsoft's HLSL compiler automatically optimises this to a bitfield extract "
"instruction.\n"
" uint mask = uint((1 << size) - 1);\n"
" return uint(val >> off) & mask;\n"
"}\n\n");
}
}
}

View file

@ -0,0 +1,24 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include "VideoCommon/ShaderGenCommon.h"
#include "VideoCommon/VideoCommon.h"
namespace UberShader
{
// Common functions across all ubershaders
void WriteUberShaderCommonHeader(ShaderCode& out, APIType api_type,
const ShaderHostConfig& host_config);
// bitfieldExtract generator for BitField types
template <typename T>
std::string BitfieldExtract(const std::string& source, T type)
{
return StringFromFormat("bitfieldExtract(%s, %u, %u)", source.c_str(),
static_cast<u32>(type.StartBit()), static_cast<u32>(type.NumBits()));
}
} // namespace UberShader

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,31 @@
// Copyright 2015 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#pragma once
#include <functional>
#include "VideoCommon/PixelShaderGen.h"
namespace UberShader
{
#pragma pack(1)
struct pixel_ubershader_uid_data
{
u32 num_texgens : 4;
u32 early_depth : 1;
u32 per_pixel_depth : 1;
u32 NumValues() const { return sizeof(pixel_ubershader_uid_data); }
};
#pragma pack()
typedef ShaderUid<pixel_ubershader_uid_data> PixelShaderUid;
PixelShaderUid GetPixelShaderUid();
ShaderCode GenPixelShader(APIType ApiType, const ShaderHostConfig& host_config,
const pixel_ubershader_uid_data* uid_data);
void EnumeratePixelShaderUids(const std::function<void(const PixelShaderUid&)>& callback);
}

View file

@ -67,6 +67,8 @@
<ClCompile Include="RenderState.cpp" />
<ClCompile Include="LightingShaderGen.cpp" />
<ClCompile Include="ShaderGenCommon.cpp" />
<ClCompile Include="UberShaderCommon.cpp" />
<ClCompile Include="UberShaderPixel.cpp" />
<ClCompile Include="Statistics.cpp" />
<ClCompile Include="GeometryShaderGen.cpp" />
<ClCompile Include="GeometryShaderManager.cpp" />
@ -109,6 +111,8 @@
<ClInclude Include="Fifo.h" />
<ClInclude Include="FPSCounter.h" />
<ClInclude Include="FramebufferManagerBase.h" />
<ClInclude Include="UberShaderCommon.h" />
<ClInclude Include="UberShaderPixel.h" />
<ClInclude Include="HiresTextures.h" />
<ClInclude Include="ImageWrite.h" />
<ClInclude Include="IndexGenerator.h" />
@ -174,4 +178,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View file

@ -179,6 +179,12 @@
<ClCompile Include="AsyncShaderCompiler.cpp">
<Filter>Util</Filter>
</ClCompile>
<ClCompile Include="UberShaderPixel.cpp">
<Filter>Shader Generators</Filter>
</ClCompile>
<ClCompile Include="UberShaderCommon.cpp">
<Filter>Shader Generators</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="CommandProcessor.h" />
@ -338,6 +344,12 @@
<ClInclude Include="AsyncShaderCompiler.h">
<Filter>Util</Filter>
</ClInclude>
<ClInclude Include="UberShaderPixel.h">
<Filter>Shader Generators</Filter>
</ClInclude>
<ClInclude Include="UberShaderCommon.h">
<Filter>Shader Generators</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />

View file

@ -204,6 +204,8 @@ struct VideoConfig final
bool bSupportsInternalResolutionFrameDumps;
bool bSupportsGPUTextureDecoding;
bool bSupportsST3CTextures;
bool bSupportsBitfield; // Needed by UberShaders, so must stay in VideoCommon
bool bSupportsDynamicSamplerIndexing; // Needed by UberShaders, so must stay in VideoCommon
} backend_info;
// Utility