Skip to content

Commit

Permalink
Merge pull request #16273 from hrydgard/multiview-ground-work
Browse files Browse the repository at this point in the history
Vulkan multiview rendering
  • Loading branch information
hrydgard authored Oct 27, 2022
2 parents e41465f + 85e7933 commit 1f1a343
Show file tree
Hide file tree
Showing 67 changed files with 1,006 additions and 374 deletions.
75 changes: 38 additions & 37 deletions Common/GPU/D3D11/thin3d_d3d11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,16 +95,13 @@ class D3D11DrawContext : public DrawContext {

// These functions should be self explanatory.
void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override;
Framebuffer *GetCurrentRenderTarget() override {
return curRenderTarget_;
}
void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) override;
void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) override;

void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override;

void InvalidateCachedState() override;

void BindTextures(int start, int count, Texture **textures) override;
void BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) override;
void BindNativeTexture(int index, void *nativeTexture) override;
void BindSamplerStates(int start, int count, SamplerState **states) override;
void BindVertexBuffers(int start, int count, Buffer **buffers, const int *offsets) override;
Expand Down Expand Up @@ -1306,35 +1303,38 @@ class D3D11Framebuffer : public Framebuffer {
Framebuffer *D3D11DrawContext::CreateFramebuffer(const FramebufferDesc &desc) {
HRESULT hr;
D3D11Framebuffer *fb = new D3D11Framebuffer(desc.width, desc.height);
if (desc.numColorAttachments) {
fb->colorFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
D3D11_TEXTURE2D_DESC descColor{};
descColor.Width = desc.width;
descColor.Height = desc.height;
descColor.MipLevels = 1;
descColor.ArraySize = 1;
descColor.Format = fb->colorFormat;
descColor.SampleDesc.Count = 1;
descColor.SampleDesc.Quality = 0;
descColor.Usage = D3D11_USAGE_DEFAULT;
descColor.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
descColor.CPUAccessFlags = 0;
descColor.MiscFlags = 0;
hr = device_->CreateTexture2D(&descColor, nullptr, &fb->colorTex);
if (FAILED(hr)) {
delete fb;
return nullptr;
}
hr = device_->CreateRenderTargetView(fb->colorTex, nullptr, &fb->colorRTView);
if (FAILED(hr)) {
delete fb;
return nullptr;
}
hr = device_->CreateShaderResourceView(fb->colorTex, nullptr, &fb->colorSRView);
if (FAILED(hr)) {
delete fb;
return nullptr;
}

// We don't (yet?) support multiview for D3D11. Not sure if there's a way to do it.
// Texture arrays are supported but we don't have any other use cases yet.
_dbg_assert_(desc.numLayers == 1);

fb->colorFormat = DXGI_FORMAT_R8G8B8A8_UNORM;
D3D11_TEXTURE2D_DESC descColor{};
descColor.Width = desc.width;
descColor.Height = desc.height;
descColor.MipLevels = 1;
descColor.ArraySize = 1;
descColor.Format = fb->colorFormat;
descColor.SampleDesc.Count = 1;
descColor.SampleDesc.Quality = 0;
descColor.Usage = D3D11_USAGE_DEFAULT;
descColor.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
descColor.CPUAccessFlags = 0;
descColor.MiscFlags = 0;
hr = device_->CreateTexture2D(&descColor, nullptr, &fb->colorTex);
if (FAILED(hr)) {
delete fb;
return nullptr;
}
hr = device_->CreateRenderTargetView(fb->colorTex, nullptr, &fb->colorRTView);
if (FAILED(hr)) {
delete fb;
return nullptr;
}
hr = device_->CreateShaderResourceView(fb->colorTex, nullptr, &fb->colorSRView);
if (FAILED(hr)) {
delete fb;
return nullptr;
}

if (desc.z_stencil) {
Expand Down Expand Up @@ -1381,7 +1381,7 @@ Framebuffer *D3D11DrawContext::CreateFramebuffer(const FramebufferDesc &desc) {
return fb;
}

void D3D11DrawContext::BindTextures(int start, int count, Texture **textures) {
void D3D11DrawContext::BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) {
// Collect the resource views from the textures.
ID3D11ShaderResourceView *views[MAX_BOUND_TEXTURES];
_assert_(start + count <= ARRAY_SIZE(views));
Expand Down Expand Up @@ -1701,8 +1701,9 @@ void D3D11DrawContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const Ren
stepId_++;
}

void D3D11DrawContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) {
_assert_(binding < MAX_BOUND_TEXTURES);
void D3D11DrawContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) {
_dbg_assert_(binding < MAX_BOUND_TEXTURES);
_dbg_assert_(layer == ALL_LAYERS || layer == 0); // No multiple layer support on D3D
D3D11Framebuffer *fb = (D3D11Framebuffer *)fbo;
switch (channelBit) {
case FBChannel::FB_COLOR_BIT:
Expand Down
20 changes: 10 additions & 10 deletions Common/GPU/D3D9/thin3d_d3d9.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -532,16 +532,13 @@ class D3D9Context : public DrawContext {

// These functions should be self explanatory.
void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override;
Framebuffer *GetCurrentRenderTarget() override {
return curRenderTarget_;
}
void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) override;

void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) override;

uintptr_t GetFramebufferAPITexture(Framebuffer *fbo, int channelBits, int attachment) override;

void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override;

void BindTextures(int start, int count, Texture **textures) override;
void BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) override;
void BindNativeTexture(int index, void *nativeTexture) override;

void BindSamplerStates(int start, int count, SamplerState **states) override {
Expand Down Expand Up @@ -749,7 +746,6 @@ D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, ID
}

caps_.deviceID = identifier_.DeviceId;
caps_.multiViewport = false;
caps_.depthRangeMinusOneToOne = false;
caps_.preferredDepthBufferFormat = DataFormat::D24_S8;
caps_.dualSourceBlend = false;
Expand Down Expand Up @@ -915,7 +911,7 @@ Texture *D3D9Context::CreateTexture(const TextureDesc &desc) {
return tex;
}

void D3D9Context::BindTextures(int start, int count, Texture **textures) {
void D3D9Context::BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) {
_assert_(start + count <= MAX_BOUND_TEXTURES);
for (int i = start; i < start + count; i++) {
D3D9Texture *tex = static_cast<D3D9Texture *>(textures[i - start]);
Expand Down Expand Up @@ -1244,6 +1240,9 @@ class D3D9Framebuffer : public Framebuffer {
};

Framebuffer *D3D9Context::CreateFramebuffer(const FramebufferDesc &desc) {
// Don't think D3D9 does array layers.
_dbg_assert_(desc.numLayers == 1);

static uint32_t id = 0;

D3D9Framebuffer *fbo = new D3D9Framebuffer(desc.width, desc.height);
Expand Down Expand Up @@ -1348,8 +1347,9 @@ uintptr_t D3D9Context::GetFramebufferAPITexture(Framebuffer *fbo, int channelBit
}
}

void D3D9Context::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) {
_assert_(binding < MAX_BOUND_TEXTURES);
void D3D9Context::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) {
_dbg_assert_(binding < MAX_BOUND_TEXTURES);
_dbg_assert_(layer == ALL_LAYERS || layer == 0); // No stereo support
D3D9Framebuffer *fb = (D3D9Framebuffer *)fbo;
switch (channelBit) {
case FB_DEPTH_BIT:
Expand Down
14 changes: 7 additions & 7 deletions Common/GPU/OpenGL/thin3d_gl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,10 +355,7 @@ class OpenGLContext : public DrawContext {

// These functions should be self explanatory.
void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override;
Framebuffer *GetCurrentRenderTarget() override {
return curRenderTarget_;
}
void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) override;
void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) override;

void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override;

Expand Down Expand Up @@ -400,7 +397,7 @@ class OpenGLContext : public DrawContext {
curPipeline_->depthStencil->stencilPass);
}

void BindTextures(int start, int count, Texture **textures) override;
void BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) override;
void BindNativeTexture(int sampler, void *nativeTexture) override;

void BindPipeline(Pipeline *pipeline) override;
Expand Down Expand Up @@ -1130,7 +1127,7 @@ Pipeline *OpenGLContext::CreateGraphicsPipeline(const PipelineDesc &desc, const
}
}

void OpenGLContext::BindTextures(int start, int count, Texture **textures) {
void OpenGLContext::BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) {
_assert_(start + count <= MAX_TEXTURE_SLOTS);
for (int i = start; i < start + count; i++) {
OpenGLTexture *glTex = static_cast<OpenGLTexture *>(textures[i - start]);
Expand Down Expand Up @@ -1390,6 +1387,9 @@ void OpenGLInputLayout::Compile(const InputLayoutDesc &desc) {
Framebuffer *OpenGLContext::CreateFramebuffer(const FramebufferDesc &desc) {
CheckGLExtensions();

// TODO: Support multiview later. (It's our only use case for multi layers).
_dbg_assert_(desc.numLayers == 1);

GLRFramebuffer *framebuffer = renderManager_.CreateFramebuffer(desc.width, desc.height, desc.z_stencil);
OpenGLFramebuffer *fbo = new OpenGLFramebuffer(&renderManager_, framebuffer);
return fbo;
Expand Down Expand Up @@ -1436,7 +1436,7 @@ bool OpenGLContext::BlitFramebuffer(Framebuffer *fbsrc, int srcX1, int srcY1, in
return true;
}

void OpenGLContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit) {
void OpenGLContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) {
OpenGLFramebuffer *fb = (OpenGLFramebuffer *)fbo;
_assert_(binding < MAX_TEXTURE_SLOTS);

Expand Down
11 changes: 9 additions & 2 deletions Common/GPU/Shader.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
#include <cstdint>
#include <cstddef> // for size_t

#include "Common/Common.h"

// GLSL_1xx and GLSL_3xx each cover a lot of sub variants. All the little quirks
// that differ are covered in ShaderLanguageDesc.
// Defined as a bitmask so stuff like GetSupportedShaderLanguages can return combinations.
// TODO: We can probably move away from this distinction soon, now that we mostly generate/translate shaders.
enum ShaderLanguage {
GLSL_1xx = 1,
GLSL_3xx = 2,
Expand All @@ -30,7 +33,6 @@ enum class ShaderStage {

const char *ShaderStageAsString(ShaderStage lang);


struct ShaderLanguageDesc {
ShaderLanguageDesc() {}
explicit ShaderLanguageDesc(ShaderLanguage lang);
Expand Down Expand Up @@ -91,13 +93,18 @@ struct UniformDef {
int index;
};

enum class SamplerFlags {
ARRAY_ON_VULKAN = 1,
};
ENUM_CLASS_BITOPS(SamplerFlags);

struct SamplerDef {
int binding; // Might only be used by some backends.
const char *name;
SamplerFlags flags;
// TODO: Might need unsigned samplers, 3d samplers, or other types in the future.
};


// For passing error messages from shader compilation (and other critical issues) back to the host.
// This can run on any thread - be aware!
// TODO: See if we can find a less generic name for this.
Expand Down
41 changes: 36 additions & 5 deletions Common/GPU/ShaderWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ void ShaderWriter::Preamble(Slice<const char *> extensions) {
switch (lang_.shaderLanguage) {
case GLSL_VULKAN:
C("#version 450\n");
if (flags_ & ShaderWriterFlags::FS_AUTO_STEREO) {
C("#extension GL_EXT_multiview : enable\n");
}
// IMPORTANT! Extensions must be the first thing after #version.
for (size_t i = 0; i < extensions.size(); i++) {
F("%s\n", extensions[i]);
Expand Down Expand Up @@ -462,6 +465,10 @@ void ShaderWriter::DeclareSamplers(Slice<SamplerDef> samplers) {
samplerDefs_ = samplers;
}

void ShaderWriter::ApplySamplerMetadata(Slice<SamplerDef> samplers) {
samplerDefs_ = samplers;
}

void ShaderWriter::DeclareTexture2D(const SamplerDef &def) {
switch (lang_.shaderLanguage) {
case HLSL_D3D11:
Expand All @@ -471,8 +478,12 @@ void ShaderWriter::DeclareTexture2D(const SamplerDef &def) {
F("sampler %s: register(s%d);\n", def.name, def.binding);
break;
case GLSL_VULKAN:
// In the thin3d descriptor set layout, textures start at 1 in set 0. Hence the +1.
F("layout(set = 0, binding = %d) uniform sampler2D %s;\n", def.binding + texBindingBase_, def.name);
// texBindingBase_ is used for the thin3d descriptor set layout, where they start at 1.
if (def.flags & SamplerFlags::ARRAY_ON_VULKAN) {
F("layout(set = 0, binding = %d) uniform sampler2DArray %s;\n", def.binding + texBindingBase_, def.name);
} else {
F("layout(set = 0, binding = %d) uniform sampler2D %s;\n", def.binding + texBindingBase_, def.name);
}
break;
default:
F("uniform sampler2D %s;\n", def.name);
Expand All @@ -492,6 +503,7 @@ void ShaderWriter::DeclareSampler2D(const SamplerDef &def) {
}

ShaderWriter &ShaderWriter::SampleTexture2D(const char *sampName, const char *uv) {
const SamplerDef *samp = GetSamplerDef(sampName);
switch (lang_.shaderLanguage) {
case HLSL_D3D11:
F("%s.Sample(%sSamp, %s)", sampName, sampName, uv);
Expand All @@ -501,13 +513,20 @@ ShaderWriter &ShaderWriter::SampleTexture2D(const char *sampName, const char *uv
break;
default:
// Note: we ignore the sampler. make sure you bound samplers to the textures correctly.
F("%s(%s, %s)", lang_.texture, sampName, uv);
if (samp && (samp->flags & SamplerFlags::ARRAY_ON_VULKAN) && lang_.shaderLanguage == GLSL_VULKAN) {
const char *index = (flags_ & ShaderWriterFlags::FS_AUTO_STEREO) ? "float(gl_ViewIndex)" : "0.0";
F("%s(%s, vec3(%s, %s))", lang_.texture, sampName, uv, index);
} else {
F("%s(%s, %s)", lang_.texture, sampName, uv);
}
break;
}
return *this;
}

ShaderWriter &ShaderWriter::SampleTexture2DOffset(const char *sampName, const char *uv, int offX, int offY) {
const SamplerDef *samp = GetSamplerDef(sampName);

switch (lang_.shaderLanguage) {
case HLSL_D3D11:
F("%s.Sample(%sSamp, %s, int2(%d, %d))", sampName, sampName, uv, offX, offY);
Expand All @@ -518,13 +537,20 @@ ShaderWriter &ShaderWriter::SampleTexture2DOffset(const char *sampName, const ch
break;
default:
// Note: we ignore the sampler. make sure you bound samplers to the textures correctly.
F("%sOffset(%s, %s, ivec2(%d, %d))", lang_.texture, sampName, uv, offX, offY);
if (samp && (samp->flags & SamplerFlags::ARRAY_ON_VULKAN) && lang_.shaderLanguage == GLSL_VULKAN) {
const char *index = (flags_ & ShaderWriterFlags::FS_AUTO_STEREO) ? "float(gl_ViewIndex)" : "0.0";
F("%sOffset(%s, vec3(%s, %s), ivec2(%d, %d))", lang_.texture, sampName, uv, index, offX, offY);
} else {
F("%sOffset(%s, %s, ivec2(%d, %d))", lang_.texture, sampName, uv, offX, offY);
}
break;
}
return *this;
}

ShaderWriter &ShaderWriter::LoadTexture2D(const char *sampName, const char *uv, int level) {
const SamplerDef *samp = GetSamplerDef(sampName);

switch (lang_.shaderLanguage) {
case HLSL_D3D11:
F("%s.Load(ivec3(%s, %d))", sampName, uv, level);
Expand All @@ -535,7 +561,12 @@ ShaderWriter &ShaderWriter::LoadTexture2D(const char *sampName, const char *uv,
break;
default:
// Note: we ignore the sampler. make sure you bound samplers to the textures correctly.
F("texelFetch(%s, %s, %d)", sampName, uv, level);
if (samp && (samp->flags & SamplerFlags::ARRAY_ON_VULKAN) && lang_.shaderLanguage == GLSL_VULKAN) {
const char *index = (flags_ & ShaderWriterFlags::FS_AUTO_STEREO) ? "gl_ViewIndex" : "0";
F("texelFetch(%s, vec3(%s, %s), %d)", sampName, uv, index, level);
} else {
F("texelFetch(%s, %s, %d)", sampName, uv, level);
}
break;
}
return *this;
Expand Down
9 changes: 8 additions & 1 deletion Common/GPU/ShaderWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,15 @@ struct VaryingDef {
enum class ShaderWriterFlags {
NONE = 0,
FS_WRITE_DEPTH = 1,
FS_AUTO_STEREO = 2, // Automatically indexes makes samplers tagged with `array` by gl_ViewIndex. Useful for stereo rendering.
};
ENUM_CLASS_BITOPS(ShaderWriterFlags);

class ShaderWriter {
public:
// Extensions are supported for both OpenGL ES and Vulkan (though of course, they're different).
ShaderWriter(char *buffer, const ShaderLanguageDesc &lang, ShaderStage stage, Slice<const char *> extensions = Slice<const char *>(), ShaderWriterFlags flags = ShaderWriterFlags::NONE) : p_(buffer), lang_(lang), stage_(stage) {
ShaderWriter(char *buffer, const ShaderLanguageDesc &lang, ShaderStage stage, Slice<const char *> extensions = Slice<const char *>(), ShaderWriterFlags flags = ShaderWriterFlags::NONE) : p_(buffer), lang_(lang), stage_(stage), flags_(flags) {
buffer[0] = '\0';
Preamble(extensions);
}
ShaderWriter(const ShaderWriter &) = delete;
Expand Down Expand Up @@ -78,6 +80,10 @@ class ShaderWriter {
// NOTE: samplers must live for the rest of ShaderWriter's lifetime. No way to express that in C++ though :(
void DeclareSamplers(Slice<SamplerDef> samplers);

// Same as DeclareSamplers, but doesn't actually declare them.
// This is currently only required by FragmentShaderGenerator.
void ApplySamplerMetadata(Slice<SamplerDef> samplers);

void ConstFloat(const char *name, float value);
void SetFlags(ShaderWriterFlags flags) { flags_ |= flags; }
void SetTexBindingBase(int base) { texBindingBase_ = base; }
Expand Down Expand Up @@ -121,6 +127,7 @@ class ShaderWriter {
char *p_;
const ShaderLanguageDesc &lang_;
const ShaderStage stage_;
Slice<SamplerDef> samplers_;
ShaderWriterFlags flags_ = ShaderWriterFlags::NONE;
Slice<SamplerDef> samplerDefs_;
int texBindingBase_ = 1;
Expand Down
Loading

0 comments on commit 1f1a343

Please sign in to comment.