mirror of
https://github.com/NoelFB/blah.git
synced 2025-02-18 12:48:27 +08:00
cleaning up D3D11 implementation
This commit is contained in:
parent
27f7134500
commit
5503198eff
@ -24,34 +24,63 @@ namespace Blah
|
||||
|
||||
struct D3D11
|
||||
{
|
||||
// main resources
|
||||
ID3D11Device* device = nullptr;
|
||||
ID3D11DeviceContext* context = nullptr;
|
||||
IDXGISwapChain* swap_chain = nullptr;
|
||||
ID3D11RenderTargetView* backbuffer = nullptr;
|
||||
ID3D11RasterizerState* rasterizer = nullptr;
|
||||
ID3D11SamplerState* sampler = nullptr;
|
||||
ID3D11DepthStencilState* depth_state = nullptr;
|
||||
|
||||
// supported renderer features
|
||||
RendererFeatures features;
|
||||
|
||||
// last backbuffer size
|
||||
Point last_size;
|
||||
|
||||
struct InputLayoutEntry
|
||||
struct StoredInputLayout
|
||||
{
|
||||
uint32_t shader_hash;
|
||||
VertexFormat format;
|
||||
ID3D11InputLayout* layout;
|
||||
};
|
||||
|
||||
struct BlendStateEntry
|
||||
struct StoredBlendState
|
||||
{
|
||||
BlendMode blend;
|
||||
ID3D11BlendState* state;
|
||||
};
|
||||
|
||||
Vector<InputLayoutEntry> layout_cache;
|
||||
Vector<BlendStateEntry> blend_cache;
|
||||
struct StoredRasterizer
|
||||
{
|
||||
Cull cull;
|
||||
bool has_scissor;
|
||||
ID3D11RasterizerState* state;
|
||||
};
|
||||
|
||||
struct StoredSampler
|
||||
{
|
||||
TextureFilter filter;
|
||||
TextureWrap wrap_x;
|
||||
TextureWrap wrap_y;
|
||||
ID3D11SamplerState* state;
|
||||
};
|
||||
|
||||
struct StoredDepthStencil
|
||||
{
|
||||
Compare depth;
|
||||
ID3D11DepthStencilState* state;
|
||||
};
|
||||
|
||||
Vector<StoredInputLayout> layout_cache;
|
||||
Vector<StoredBlendState> blend_cache;
|
||||
Vector<StoredRasterizer> rasterizer_cache;
|
||||
Vector<StoredSampler> sampler_cache;
|
||||
Vector<StoredDepthStencil> depthstencil_cache;
|
||||
|
||||
ID3D11InputLayout* get_layout(D3D11_Shader* shader, const VertexFormat& format);
|
||||
ID3D11BlendState* get_blend(const BlendMode& blend);
|
||||
ID3D11RasterizerState* get_rasterizer(const RenderPass& pass);
|
||||
ID3D11SamplerState* get_sampler(const TextureRef& texture);
|
||||
ID3D11DepthStencilState* get_depthstencil(const RenderPass& pass);
|
||||
};
|
||||
|
||||
D3D11 state;
|
||||
@ -338,7 +367,7 @@ namespace Blah
|
||||
|
||||
virtual void get_data(unsigned char* data) override
|
||||
{
|
||||
|
||||
BLAH_ASSERT(false, "Not Implemented Yet");
|
||||
}
|
||||
|
||||
virtual bool is_framebuffer() const override
|
||||
@ -451,8 +480,8 @@ namespace Blah
|
||||
// compile vertex shader
|
||||
{
|
||||
hr = D3DCompile(
|
||||
data->vertex,
|
||||
strlen(data->vertex),
|
||||
data->vertex.cstr(),
|
||||
data->vertex.length(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
@ -478,8 +507,8 @@ namespace Blah
|
||||
// compile fragment shader
|
||||
{
|
||||
hr = D3DCompile(
|
||||
data->fragment,
|
||||
strlen(data->fragment),
|
||||
data->fragment.cstr(),
|
||||
data->fragment.length(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
@ -744,9 +773,9 @@ namespace Blah
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.SampleDesc.Quality = 0;
|
||||
desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
desc.BufferCount = 2;
|
||||
desc.BufferCount = 1;
|
||||
desc.OutputWindow = (HWND)PlatformBackend::d3d11_get_hwnd();
|
||||
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
||||
//desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
||||
desc.Windowed = true;
|
||||
|
||||
D3D_FEATURE_LEVEL feature_level;
|
||||
@ -938,28 +967,27 @@ namespace Blah
|
||||
}
|
||||
|
||||
// Depth
|
||||
// TODO: Doesn't actually assign proper values
|
||||
// TODO: Cache this
|
||||
{
|
||||
if (state.depth_state)
|
||||
state.depth_state->Release();
|
||||
|
||||
D3D11_DEPTH_STENCIL_DESC desc = {};
|
||||
desc.DepthEnable = FALSE;
|
||||
desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
|
||||
desc.DepthFunc = D3D11_COMPARISON_NEVER;
|
||||
|
||||
state.device->CreateDepthStencilState(&desc, &state.depth_state);
|
||||
ctx->OMSetDepthStencilState(state.depth_state, 0);
|
||||
auto depthstencil = state.get_depthstencil(pass);
|
||||
if (depthstencil)
|
||||
ctx->OMSetDepthStencilState(depthstencil, 0);
|
||||
}
|
||||
|
||||
// Blend Mode
|
||||
{
|
||||
auto blend = state.get_blend(pass.blend);
|
||||
auto color = Color::from_rgba(pass.blend.rgba);
|
||||
float factor[4]{ color.r / 255.0f, color.g / 255.0f, color.b / 255.0f, color.a / 255.0f };
|
||||
auto mask = 0xffffffff;
|
||||
ctx->OMSetBlendState(blend, factor, mask);
|
||||
if (blend)
|
||||
{
|
||||
auto color = Color::from_rgba(pass.blend.rgba);
|
||||
float factor[4]{ color.r / 255.0f, color.g / 255.0f, color.b / 255.0f, color.a / 255.0f };
|
||||
auto mask = 0xffffffff;
|
||||
ctx->OMSetBlendState(blend, factor, mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if we failed to create a blend mode for some reason
|
||||
ctx->OMSetBlendState(nullptr, nullptr, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1027,21 +1055,24 @@ namespace Blah
|
||||
}
|
||||
|
||||
// Sampler
|
||||
// TODO: Doesn't actually assign proper values
|
||||
// TODO: Cache this
|
||||
|
||||
// TODO:
|
||||
// This is incorrect! Textures and Samplers are separate in HLSL.
|
||||
// For now, just assuming there's only 1 Sampler and we set it to
|
||||
// the properties of the first Texture ...
|
||||
|
||||
// I think most modern APIs separate these, where as OpenGL makes
|
||||
// them the same (afaik). Either we need to separate these in our
|
||||
// API, or find some work around here.
|
||||
|
||||
// I think our API should change to add Samplers as a unique resource,
|
||||
// which matches D3D11 (and I assume Metal / Vulkan)
|
||||
|
||||
if (textures.size() > 0 && textures[0])
|
||||
{
|
||||
if (state.sampler)
|
||||
state.sampler->Release();
|
||||
|
||||
D3D11_SAMPLER_DESC samplerDesc = {};
|
||||
samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
|
||||
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
|
||||
|
||||
state.device->CreateSamplerState(&samplerDesc, &state.sampler);
|
||||
ctx->PSSetSamplers(0, 1, &state.sampler);
|
||||
auto sampler = state.get_sampler(textures[0]);
|
||||
if (sampler)
|
||||
ctx->PSSetSamplers(0, 1, &sampler);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1072,26 +1103,10 @@ namespace Blah
|
||||
}
|
||||
|
||||
// Rasterizer
|
||||
// TODO: Doesn't actually assign proper values
|
||||
// TODO: Cache this
|
||||
{
|
||||
if (state.rasterizer)
|
||||
state.rasterizer->Release();
|
||||
|
||||
D3D11_RASTERIZER_DESC rasterizerDesc = {};
|
||||
rasterizerDesc.FillMode = D3D11_FILL_SOLID;
|
||||
rasterizerDesc.CullMode = D3D11_CULL_NONE;
|
||||
rasterizerDesc.FrontCounterClockwise = true;
|
||||
rasterizerDesc.DepthBias = 0;
|
||||
rasterizerDesc.DepthBiasClamp = 0;
|
||||
rasterizerDesc.SlopeScaledDepthBias = 0;
|
||||
rasterizerDesc.DepthClipEnable = false;
|
||||
rasterizerDesc.ScissorEnable = pass.has_scissor;
|
||||
rasterizerDesc.MultisampleEnable = false;
|
||||
rasterizerDesc.AntialiasedLineEnable = false;
|
||||
|
||||
state.device->CreateRasterizerState(&rasterizerDesc, &state.rasterizer);
|
||||
ctx->RSSetState(state.rasterizer);
|
||||
auto rasterizer = state.get_rasterizer(pass);
|
||||
if (rasterizer)
|
||||
ctx->RSSetState(rasterizer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1255,6 +1270,136 @@ namespace Blah
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ID3D11SamplerState* D3D11::get_sampler(const TextureRef& texture)
|
||||
{
|
||||
auto filter = texture->get_filter();
|
||||
auto wrap_x = texture->get_wrap_x();
|
||||
auto wrap_y = texture->get_wrap_y();
|
||||
|
||||
for (auto& it : sampler_cache)
|
||||
if (it.filter == filter && it.wrap_x == wrap_x && it.wrap_y == wrap_y)
|
||||
return it.state;
|
||||
|
||||
D3D11_SAMPLER_DESC desc = {};
|
||||
desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
|
||||
desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
desc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
|
||||
desc.ComparisonFunc = D3D11_COMPARISON_NEVER;
|
||||
|
||||
switch (filter)
|
||||
{
|
||||
case TextureFilter::Nearest: desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; break;
|
||||
case TextureFilter::Linear: desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; break;
|
||||
}
|
||||
|
||||
switch (wrap_x)
|
||||
{
|
||||
case TextureWrap::Clamp: desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; break;
|
||||
case TextureWrap::Repeat: desc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; break;
|
||||
}
|
||||
|
||||
switch (wrap_y)
|
||||
{
|
||||
case TextureWrap::Clamp: desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; break;
|
||||
case TextureWrap::Repeat: desc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; break;
|
||||
}
|
||||
|
||||
ID3D11SamplerState* result;
|
||||
auto hr = state.device->CreateSamplerState(&desc, &result);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
auto entry = sampler_cache.expand();
|
||||
entry->filter = filter;
|
||||
entry->wrap_x = wrap_x;
|
||||
entry->wrap_y = wrap_y;
|
||||
entry->state = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ID3D11RasterizerState* D3D11::get_rasterizer(const RenderPass& pass)
|
||||
{
|
||||
for (auto& it : rasterizer_cache)
|
||||
if (it.cull == pass.cull && it.has_scissor == pass.has_scissor)
|
||||
return it.state;
|
||||
|
||||
D3D11_RASTERIZER_DESC desc = {};
|
||||
desc.FillMode = D3D11_FILL_SOLID;
|
||||
desc.CullMode = D3D11_CULL_NONE;
|
||||
|
||||
switch (pass.cull)
|
||||
{
|
||||
case Cull::None: desc.CullMode = D3D11_CULL_NONE; break;
|
||||
case Cull::Front: desc.CullMode = D3D11_CULL_FRONT; break;
|
||||
case Cull::Back: desc.CullMode = D3D11_CULL_BACK; break;
|
||||
}
|
||||
|
||||
desc.FrontCounterClockwise = true;
|
||||
desc.DepthBias = 0;
|
||||
desc.DepthBiasClamp = 0;
|
||||
desc.SlopeScaledDepthBias = 0;
|
||||
desc.DepthClipEnable = false;
|
||||
desc.ScissorEnable = pass.has_scissor;
|
||||
desc.MultisampleEnable = false;
|
||||
desc.AntialiasedLineEnable = false;
|
||||
|
||||
ID3D11RasterizerState* result;
|
||||
auto hr = state.device->CreateRasterizerState(&desc, &result);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
auto entry = rasterizer_cache.expand();
|
||||
entry->cull = pass.cull;
|
||||
entry->has_scissor = pass.has_scissor;
|
||||
entry->state = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ID3D11DepthStencilState* D3D11::get_depthstencil(const RenderPass& pass)
|
||||
{
|
||||
for (auto& it : depthstencil_cache)
|
||||
if (it.depth == pass.depth)
|
||||
return it.state;
|
||||
|
||||
D3D11_DEPTH_STENCIL_DESC desc = {};
|
||||
desc.DepthEnable = pass.depth != Compare::None;
|
||||
desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
|
||||
desc.DepthFunc = D3D11_COMPARISON_NEVER;
|
||||
|
||||
switch (pass.depth)
|
||||
{
|
||||
case Compare::None: desc.DepthFunc = D3D11_COMPARISON_NEVER; break;
|
||||
case Compare::Always: desc.DepthFunc = D3D11_COMPARISON_ALWAYS; break;
|
||||
case Compare::Never: desc.DepthFunc = D3D11_COMPARISON_NEVER; break;
|
||||
case Compare::Less: desc.DepthFunc = D3D11_COMPARISON_LESS; break;
|
||||
case Compare::Equal: desc.DepthFunc = D3D11_COMPARISON_EQUAL; break;
|
||||
case Compare::LessOrEqual: desc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL; break;
|
||||
case Compare::Greater: desc.DepthFunc = D3D11_COMPARISON_GREATER; break;
|
||||
case Compare::NotEqual: desc.DepthFunc = D3D11_COMPARISON_NOT_EQUAL; break;
|
||||
case Compare::GreatorOrEqual: desc.DepthFunc = D3D11_COMPARISON_GREATER_EQUAL; break;
|
||||
}
|
||||
|
||||
ID3D11DepthStencilState* result;
|
||||
auto hr = state.device->CreateDepthStencilState(&desc, &result);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
auto entry = depthstencil_cache.expand();
|
||||
entry->depth = pass.depth;
|
||||
entry->state = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BLAH_USE_D3D11
|
||||
|
@ -807,13 +807,13 @@ namespace Blah
|
||||
{
|
||||
m_id = 0;
|
||||
|
||||
if (data->vertex == nullptr)
|
||||
if (data->vertex.length() <= 0)
|
||||
{
|
||||
Log::error("Vertex Shader is required");
|
||||
return;
|
||||
}
|
||||
|
||||
if (data->fragment == nullptr)
|
||||
if (data->fragment.length() <= 0)
|
||||
{
|
||||
Log::error("Fragment Shader is required");
|
||||
return;
|
||||
@ -824,7 +824,7 @@ namespace Blah
|
||||
|
||||
GLuint vertex_shader = gl.CreateShader(GL_VERTEX_SHADER);
|
||||
{
|
||||
const GLchar* source = (const GLchar*)data->vertex;
|
||||
const GLchar* source = (const GLchar*)data->vertex.cstr();
|
||||
gl.ShaderSource(vertex_shader, 1, &source, nullptr);
|
||||
gl.CompileShader(vertex_shader);
|
||||
gl.GetShaderInfoLog(vertex_shader, 1024, &log_length, log);
|
||||
@ -839,7 +839,7 @@ namespace Blah
|
||||
|
||||
GLuint fragment_shader = gl.CreateShader(GL_FRAGMENT_SHADER);
|
||||
{
|
||||
const GLchar* source = (const GLchar*)data->fragment;
|
||||
const GLchar* source = (const GLchar*)data->fragment.cstr();
|
||||
gl.ShaderSource(fragment_shader, 1, &source, nullptr);
|
||||
gl.CompileShader(fragment_shader);
|
||||
gl.GetShaderInfoLog(fragment_shader, 1024, &log_length, log);
|
||||
|
@ -29,7 +29,6 @@ namespace Blah
|
||||
None = 0,
|
||||
Front = 1,
|
||||
Back = 2,
|
||||
Both = 3
|
||||
};
|
||||
|
||||
struct RenderPass
|
||||
|
@ -5,5 +5,31 @@ using namespace Blah;
|
||||
|
||||
ShaderRef Shader::create(const ShaderData* data)
|
||||
{
|
||||
return GraphicsBackend::create_shader(data);
|
||||
// get the shader
|
||||
auto shader = GraphicsBackend::create_shader(data);
|
||||
|
||||
// validate the shader
|
||||
if (shader)
|
||||
{
|
||||
auto& uniforms = shader->uniforms();
|
||||
|
||||
// make sure its uniforms are valid
|
||||
for (auto& it : uniforms)
|
||||
if (it.type == UniformType::None)
|
||||
{
|
||||
BLAH_ERROR_FMT("Uniform '%s' has an invalid type!\n\tOnly Float/Float2/Float3/Float4/Mat3x2/Mat4x4/Texture are allowed!", it.name.cstr());
|
||||
return ShaderRef();
|
||||
}
|
||||
|
||||
// make sure uniform names don't overlap
|
||||
for (int i = 0; i < uniforms.size(); i ++)
|
||||
for (int j = i + 1; j < uniforms.size(); j ++)
|
||||
if (uniforms[i].name == uniforms[j].name)
|
||||
{
|
||||
BLAH_ERROR_FMT("Shader Uniform names '%s' overlap! All Names must be unique.", uniforms[0].name.cstr());
|
||||
return ShaderRef();
|
||||
}
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
@ -59,10 +59,10 @@ namespace Blah
|
||||
};
|
||||
|
||||
// Vertex Shader Program data
|
||||
const char* vertex;
|
||||
String vertex;
|
||||
|
||||
// Fragment Shader Program data
|
||||
const char* fragment;
|
||||
String fragment;
|
||||
|
||||
// HLSL Attributes - required for D3D11
|
||||
StackVector<HLSL_Attribute, 16> hlsl_attributes;
|
||||
|
@ -7,6 +7,9 @@
|
||||
#define BLAH_ERROR(message) \
|
||||
do { Log::error(message "\n\tin file: %s:%d", __FILE__, __LINE__); abort(); } while(0)
|
||||
|
||||
#define BLAH_ERROR_FMT(message, ...) \
|
||||
do { Log::error(message "\n\tin file: %s:%d", __VA_ARGS__, __FILE__, __LINE__); abort(); } while(0)
|
||||
|
||||
#define BLAH_ASSERT(condition, message) \
|
||||
do { if (!(condition)) { BLAH_ERROR(message); } } while(0)
|
||||
|
||||
@ -15,6 +18,9 @@
|
||||
#define BLAH_ERROR(message) \
|
||||
Log::error(message "\n\tin file: %s:%d", __FILE__, __LINE__)
|
||||
|
||||
#define BLAH_ERROR_FMT(message, ...) \
|
||||
Log::error(message "\n\tin file: %s:%d", __VA_ARGS__, __FILE__, __LINE__)
|
||||
|
||||
#define BLAH_ASSERT(condition, message) \
|
||||
do { } while(false)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user