I've been debugging this for about a day now and everything seems okay. Im trying to get a simple tringle to render, but nothing is showing up. I have a Pixel Shader and a Vertex Shader which is compiling okay.
I will supply all of the code, any help would be greatly appreciated.
Main C++ File:
#include <windows.h>
#include <D3D11_1.h>
static int ScreenWidth = 1280;
static int ScreenHeight = 720;
static bool GlobalRunning;
static ID3D11Device *Device;
static ID3D11DeviceContext *DeviceContext;
static IDXGISwapChain1 *SwapChain;
static ID3D11RenderTargetView *RenderTargetView;
#define Assert(Expression) if(!(Expression)) { *(int *)0 = 0;}
struct vec3
{
float X;
float Y;
float Z;
};
struct vec4
{
float X;
float Y;
float Z;
float W;
};
struct vertex
{
vec3 Position;
vec4 Color;
};
static int
SafeTruncateUInt64(LONG Value)
{
Assert(Value <= 0xFFFFFFFF);
int Result = (int)Value;
return(Result);
}
struct read_file_result
{
void *Contents;
int ContentsSize;
};
static read_file_result
Win32LoadEntireFile(char *Filename)
{
read_file_result Result = {};
HANDLE File = CreateFileA(Filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if(File != INVALID_HANDLE_VALUE)
{
LARGE_INTEGER FileSize;
if(GetFileSizeEx(File, &FileSize))
{
int FileSize32 = SafeTruncateUInt64(FileSize.QuadPart);
Result.Contents = VirtualAlloc(0, FileSize32, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
if(Result.Contents)
{
DWORD BytesRead;
if(ReadFile(File, Result.Contents, FileSize32, &BytesRead, 0) && BytesRead == FileSize32)
{
Result.ContentsSize = FileSize32;
}
else
{
// TODO(zak): Logging
}
}
else
{
// TODO(zak): Logging
}
}
else
{
// TODO(zak): Logging
}
}
else
{
// TODO(zak): Logging
}
return(Result);
}
static LRESULT CALLBACK
Win32MainWindowCallback(HWND Window,
UINT Message,
WPARAM WParam,
LPARAM LParam)
{
LRESULT Result = 0;
switch(Message)
{
case WM_ACTIVATEAPP:
{
// TODO(zak): Handle this
} break;
case WM_SIZE:
{
ScreenWidth = LOWORD(LParam);
ScreenHeight = HIWORD(LParam);
RenderTargetView->Release();
SwapChain->ResizeBuffers(0, ScreenWidth, ScreenHeight, DXGI_FORMAT_UNKNOWN, 0);
ID3D11Texture2D *BackBuffer;
if(SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **)&BackBuffer) == S_OK)
{
Device->CreateRenderTargetView(BackBuffer, 0, &RenderTargetView);
BackBuffer->Release();
}
} break;
case WM_QUIT:
{
GlobalRunning = false;
} break;
case WM_DESTROY:
{
GlobalRunning = false;
} break;
default:
{
Result = DefWindowProcA(Window, Message, WParam, LParam);
}
}
return(Result);
}
int CALLBACK
WinMain(HINSTANCE Instance,
HINSTANCE PrevInstance,
LPSTR CommandLine,
int ShowCode)
{
WNDCLASSA WindowClass = {};
WindowClass.style = CS_HREDRAW|CS_VREDRAW;
WindowClass.lpfnWndProc = Win32MainWindowCallback;
WindowClass.hInstance = Instance;
WindowClass.lpszClassName = "DXPlaygroundWindowClass";
if(RegisterClassA(&WindowClass))
{
RECT WindowRect;
WindowRect.top = 0;
WindowRect.bottom = ScreenHeight;
WindowRect.left = 0;
WindowRect.right = ScreenWidth;
AdjustWindowRect(&WindowRect, WS_OVERLAPPEDWINDOW, 0);
HWND Window =
CreateWindowExA(0,
WindowClass.lpszClassName,
"D3D Playground",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
WindowRect.right - WindowRect.left,
WindowRect.bottom - WindowRect.top,
0, 0, Instance, 0);
if(Window)
{
D3D_FEATURE_LEVEL FeatureLevelsRequested[3]
{
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
};
D3D_FEATURE_LEVEL FeatureLevelReturned;
if(D3D11CreateDevice(0,
D3D_DRIVER_TYPE_HARDWARE,
0,
0,
FeatureLevelsRequested,
3,
D3D11_SDK_VERSION,
&Device,
&FeatureLevelReturned,
&DeviceContext) == S_OK)
{
IDXGIFactory2 *Factory;
if(CreateDXGIFactory(__uuidof(IDXGIFactory2), (void **)&Factory) == S_OK)
{
DXGI_SWAP_CHAIN_DESC1 SwapChainDescription = {};
SwapChainDescription.Width = ScreenWidth;
SwapChainDescription.Height = ScreenHeight;
SwapChainDescription.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
DXGI_SAMPLE_DESC SampleDescription = {};
SampleDescription.Count = 1;
SampleDescription.Quality = 0;
SwapChainDescription.SampleDesc = SampleDescription;
SwapChainDescription.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
SwapChainDescription.BufferCount = 2;
SwapChainDescription.Scaling = DXGI_SCALING_STRETCH;
SwapChainDescription.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
if(Factory->CreateSwapChainForHwnd(Device, Window,
&SwapChainDescription,
0, 0, &SwapChain) == S_OK)
{
ID3D11Texture2D *BackBuffer;
if(SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D),
(void **)&BackBuffer) == S_OK)
{
Device->CreateRenderTargetView(BackBuffer, 0, &RenderTargetView);
BackBuffer->Release();
}
ShowWindow(Window, SW_SHOWNORMAL);
read_file_result VertexShaderFile = Win32LoadEntireFile("shaders/testvertex.fxo");
read_file_result PixelShaderFile = Win32LoadEntireFile("shaders/testpixel.fxo");
ID3D11VertexShader *VertexShader;
ID3D11PixelShader *PixelShader;
Device->CreateVertexShader(VertexShaderFile.Contents,
VertexShaderFile.ContentsSize, 0, &VertexShader);
Device->CreatePixelShader(PixelShaderFile.Contents,
PixelShaderFile.ContentsSize, 0, &PixelShader);
DeviceContext->VSSetShader(VertexShader, 0, 0);
DeviceContext->PSSetShader(PixelShader, 0, 0);
D3D11_INPUT_ELEMENT_DESC ied[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
};
ID3D11InputLayout *Layout;
Device->CreateInputLayout(ied, 2, VertexShaderFile.Contents, VertexShaderFile.ContentsSize, &Layout);
DeviceContext->IASetInputLayout(Layout);
vertex OurVerticies[3] = {};
OurVerticies[0].Position.Y = 0.5f;
OurVerticies[0].Color.X = 1.0f;
OurVerticies[0].Color.W = 1.0f;
OurVerticies[1].Position.X = 0.45f;
OurVerticies[1].Position.Y = -0.5f;
OurVerticies[1].Color.Y = 1.0f;
OurVerticies[1].Color.W = 1.0f;
OurVerticies[2].Position.X = -0.45f;
OurVerticies[2].Position.Y = -0.5f;
OurVerticies[2].Color.Z = 1.0f;
OurVerticies[2].Color.W = 1.0f;
ID3D11Buffer *VertexBuffer = 0;
D3D11_BUFFER_DESC BufferDescription = {};
BufferDescription.Usage = D3D11_USAGE_DYNAMIC;
BufferDescription.ByteWidth = sizeof(vertex) * 3;
BufferDescription.BindFlags = D3D11_BIND_VERTEX_BUFFER;
BufferDescription.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
Device->CreateBuffer(&BufferDescription, 0, &VertexBuffer);
D3D11_MAPPED_SUBRESOURCE MappedSubresource;
DeviceContext->Map(VertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedSubresource);
CopyMemory(MappedSubresource.pData, OurVerticies, sizeof(OurVerticies));
DeviceContext->Unmap(VertexBuffer, 0);
GlobalRunning = true;
while(GlobalRunning)
{
MSG Message;
while(PeekMessageA(&Message, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&Message);
DispatchMessageA(&Message);
}
FLOAT ClearColor[] = {0.0f, 0.0f, 1.0f, 1.0f};
DeviceContext->ClearRenderTargetView(RenderTargetView, ClearColor);
DeviceContext->OMSetRenderTargets(1, &RenderTargetView, 0);
UINT Stride = sizeof(vertex);
UINT Offset = 0;
DeviceContext->IASetVertexBuffers(0, 1, &VertexBuffer, &Stride, &Offset);
DeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
DeviceContext->Draw(3, 0);
SwapChain->Present(1, 0);
}
}
else
{
// TODO(zak): Logging
}
}
else
{
// TODO(zak): Logging
}
}
else
{
// TODO(zak): Logging
}
}
else
{
// TODO(zak): Logging
}
}
else
{
// TODO(zak): Logging
}
return(0);
}
Pixel Shader
float4 main(float4 position : SV_POSITION, float4 color : COLOR) : SV_TARGET
{
return color;
}
Vertex Shader
struct VOut
{
float4 position : SV_POSITION;
float4 color : COLOR;
};
VOut main(float4 position : POSITION, float4 color : COLOR)
{
VOut output;
output.position = position;
output.color = color;
return output;
}
The code you've posted is missing error checking of the HRESULT on most of the Direct3D calls. If a COM call returns a void you don't have to handle the error, otherwise you do. You can do this with the SUCCEEDED macro, the FAILED macro, or with the ThrowIfFailed helper. I'd bet at least one of your calls is failing and you don't notice because you aren't checking for a failure result.
Second, you should enable the Debug device by passing D3D11_CREATE_DEVICE_DEBUG as the 4th parameter. Then look for ERROR or CORRUPTION messages in your debug output. See this post.
Not sure where you got your original "hello world" tutorial, but you should take a look at the Direct3D Game VS Templates and the DirectX Tool Kit.
Related
My intuition is that if X is drawn before Y then X will be under Y. However, my code seems to always draw things drawn by D2D under things drawn by D3D11. This happens regardless of whether I'm using a depth buffer or not. Why is it doing this and how can I make D2D draw over D3D11 so that I can use D2D to create a GUI overlay?
Here is the smallest reproducible sample I could make:
#include <Windows.h>
#include <string>
#include <d3d11.h>
#include <d2d1.h>
#include <wrl.h>
#include <d3dcompiler.h>
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d2d1.lib")
#pragma comment(lib, "d3dcompiler.lib")
using namespace std;
using namespace Microsoft::WRL;
// Globals
HWND g_hWnd;
// D3D11
ComPtr<ID3D11Device> g_device;
ComPtr<ID3D11DeviceContext> g_context;
ComPtr<IDXGISwapChain> g_swapChain;
ComPtr<ID3D11RenderTargetView> g_renderTarget;
ComPtr<ID3D11Buffer> g_triangleVertexBuffer;
// D2D
ComPtr<ID2D1RenderTarget> g_renderTarget2D;
ComPtr<ID2D1Factory> g_factory2D;
// Utilities
constexpr const char* VERTEX_SHADER_CODE =
R"(
float4 main(float2 pos : POSITION) : SV_Position
{
return float4(pos, 0.0f, 1.0f);
}
)";
constexpr const char* PIXEL_SHADER_CODE =
R"(
float4 main() : SV_Target
{
return float4(1.0f, 0.0f, 0.0f, 1.0f);
}
)";
struct Vector2f
{
float x, y;
Vector2f() : x(0.0f), y(0.0f) { }
Vector2f(float x, float y) : x(x), y(y) { }
};
void AssertHResult(HRESULT hr, string errorMsg)
{
if (FAILED(hr))
throw std::exception(errorMsg.c_str());
}
void CompileShaderFromString(string code, string shaderType, ID3DBlob** output)
{
AssertHResult(D3DCompile(
code.c_str(),
code.length(),
nullptr,
nullptr,
nullptr,
"main",
shaderType.c_str(),
#ifdef _DEBUG
D3DCOMPILE_DEBUG |
#else
D3DCOMPILE_OPTIMIZATION_LEVEL3 |
#endif
D3DCOMPILE_ENABLE_STRICTNESS,
NULL,
output,
nullptr
), "Failed to compile shader");
}
// Graphics stuff
void InitializeD2D()
{
// Get swap chain surface
ComPtr<IDXGISurface> surface;
AssertHResult(g_swapChain->GetBuffer(
0,
__uuidof(IDXGISurface),
static_cast<void**>(&surface)
), "Failed to get surface of swap chain");
// Create factory
AssertHResult(D2D1CreateFactory<ID2D1Factory>(
D2D1_FACTORY_TYPE_SINGLE_THREADED,
&g_factory2D
), "Failed to create factory");
// Create render target
D2D1_RENDER_TARGET_PROPERTIES rtDesc = D2D1::RenderTargetProperties(
D2D1_RENDER_TARGET_TYPE_HARDWARE,
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED)
);
AssertHResult(g_factory2D->CreateDxgiSurfaceRenderTarget(
surface.Get(),
&rtDesc,
&g_renderTarget2D
), "Failed to create D2D render target");
}
void InitializeD3D()
{
// Get window dimensions
RECT rect{};
GetClientRect(g_hWnd, &rect);
float width = static_cast<float>(rect.right - rect.left);
float height = static_cast<float>(rect.bottom - rect.top);
// Create device, context, and swapchain
DXGI_SWAP_CHAIN_DESC scDesc{};
scDesc.BufferCount = 1;
scDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
scDesc.BufferDesc.Width = static_cast<UINT>(width);
scDesc.BufferDesc.Height = static_cast<UINT>(height);
scDesc.BufferDesc.RefreshRate.Numerator = 0;
scDesc.BufferDesc.RefreshRate.Denominator = 0;
scDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
scDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
scDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
scDesc.Flags = NULL;
scDesc.OutputWindow = g_hWnd;
scDesc.SampleDesc.Count = 1;
scDesc.SampleDesc.Quality = 0;
scDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
scDesc.Windowed = true;
AssertHResult(D3D11CreateDeviceAndSwapChain(
nullptr,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
#ifdef _DEBUG
D3D11_CREATE_DEVICE_DEBUG |
#endif
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
nullptr,
NULL,
D3D11_SDK_VERSION,
&scDesc,
&g_swapChain,
&g_device,
nullptr,
&g_context
), "Failed to create device and swapchain");
// Create render target
ComPtr<ID3D11Resource> backBuffer;
AssertHResult(g_swapChain->GetBuffer(
0,
__uuidof(ID3D11Resource),
static_cast<void**>(&backBuffer)
), "Failed to get back buffer of swapchain");
AssertHResult(g_device->CreateRenderTargetView(
backBuffer.Get(),
nullptr,
&g_renderTarget
), "Failed to create render target view");
// Bind render target
g_context->OMSetRenderTargets(
1,
g_renderTarget.GetAddressOf(),
nullptr
);
// Bind viewport
D3D11_VIEWPORT viewport{};
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
viewport.TopLeftX = 0.0f;
viewport.TopLeftY = 0.0f;
viewport.Width = width;
viewport.Height = height;
g_context->RSSetViewports(
1,
&viewport
);
}
void InitializeD3DTriangle()
{
// Create vertex buffer
Vector2f vertices[3] =
{
Vector2f(-0.5f, -0.5f),
Vector2f(0.0f, 0.5f),
Vector2f(0.5f, -0.5f)
};
D3D11_BUFFER_DESC vbDesc{};
vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vbDesc.ByteWidth = static_cast<UINT>(sizeof(Vector2f) * 3);
vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
vbDesc.MiscFlags = NULL;
vbDesc.StructureByteStride = sizeof(Vector2f);
vbDesc.Usage = D3D11_USAGE_DYNAMIC;
D3D11_SUBRESOURCE_DATA vbData{};
vbData.pSysMem = vertices;
AssertHResult(g_device->CreateBuffer(
&vbDesc,
&vbData,
&g_triangleVertexBuffer
), "Failed to create vertex buffer");
// Bind vertex buffer
const UINT offset = 0;
const UINT stride = sizeof(Vector2f);
g_context->IASetVertexBuffers(
0,
1,
g_triangleVertexBuffer.GetAddressOf(),
&stride,
&offset
);
// Create and bind vertex shader
ComPtr<ID3DBlob> vsBlob;
ComPtr<ID3D11VertexShader> vertexShader;
CompileShaderFromString(
VERTEX_SHADER_CODE,
"vs_4_0",
&vsBlob
);
AssertHResult(g_device->CreateVertexShader(
vsBlob->GetBufferPointer(),
vsBlob->GetBufferSize(),
nullptr,
&vertexShader
), "Failed to create vertex shader");
g_context->VSSetShader(
vertexShader.Get(),
nullptr,
NULL
);
// Create and bind pixel shader
ComPtr<ID3DBlob> pxBlob;
ComPtr<ID3D11PixelShader> pixelShader;
CompileShaderFromString(
PIXEL_SHADER_CODE,
"ps_4_0",
&pxBlob
);
AssertHResult(g_device->CreatePixelShader(
pxBlob->GetBufferPointer(),
pxBlob->GetBufferSize(),
nullptr,
&pixelShader
), "Failed to create pixel shader");
g_context->PSSetShader(
pixelShader.Get(),
nullptr,
NULL
);
// Set topology
g_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY::D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// Create input layout
ComPtr<ID3D11InputLayout> inputLayout;
D3D11_INPUT_ELEMENT_DESC ilDesc{};
ilDesc.AlignedByteOffset = 0;
ilDesc.Format = DXGI_FORMAT_R32G32_FLOAT;
ilDesc.SemanticName = "POSITION";
ilDesc.SemanticIndex = 0;
ilDesc.InputSlot = 0;
ilDesc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
ilDesc.InstanceDataStepRate = 0;
AssertHResult(g_device->CreateInputLayout(
&ilDesc,
1,
vsBlob->GetBufferPointer(),
vsBlob->GetBufferSize(),
&inputLayout
), "Failed to create input layout");
// Bind input layout
g_context->IASetInputLayout(inputLayout.Get());
}
// Windows
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hWnd, msg, wParam, lParam);
}
return 0;
}
void InitializeWindow(HINSTANCE hInst, int width, int height)
{
// Register window class
WNDCLASSEXW wc{};
wc.cbSize = sizeof(WNDCLASSEXW);
wc.hCursor = LoadCursorW(NULL, IDC_ARROW);
wc.hInstance = hInst;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = L"MainWindow";
wc.style = CS_OWNDC;
RegisterClassExW(&wc);
// Adjust width and height to be client area instead of window area
RECT rc{};
rc.left = 0;
rc.top = 0;
rc.right = width;
rc.bottom = height;
constexpr auto ws = WS_OVERLAPPEDWINDOW;
AdjustWindowRectEx(
&rc,
ws,
false,
NULL
);
// Instantiate and show window
g_hWnd = CreateWindowExW(
NULL,
L"MainWindow",
L"Window Title",
ws,
CW_USEDEFAULT,
CW_USEDEFAULT,
static_cast<int>(rc.right - rc.left),
static_cast<int>(rc.bottom - rc.top),
NULL,
NULL,
hInst,
nullptr
);
ShowWindow(g_hWnd, SW_SHOW);
}
// Driver code
void Update()
{
// Begin frame
g_renderTarget2D->BeginDraw();
// Clear screen to black
D2D1_COLOR_F bgColour = { 0.0f, 0.0f, 0.0f, 1.0f };
g_renderTarget2D->Clear(bgColour);
// Draw D3D triangle
g_context->Draw(
3,
0
);
// Draw D2D rectangle
D2D_RECT_F rect{};
rect.bottom = 500;
rect.top = 300;
rect.left = 100;
rect.right = 700;
D2D1_COLOR_F rectColour = { 0.0f, 1.0f, 0.0f, 1.0f };
ComPtr<ID2D1SolidColorBrush> brush;
g_renderTarget2D->CreateSolidColorBrush(
rectColour,
&brush
);
g_renderTarget2D->FillRectangle(
rect,
brush.Get()
);
// End frame
AssertHResult(g_swapChain->Present(
1,
NULL
), "Failed to present swapchain");
g_renderTarget2D->EndDraw();
}
int APIENTRY wWinMain(HINSTANCE hInst, HINSTANCE prevInst, LPWSTR cmdArgs, int cmdShow)
{
InitializeWindow(hInst, 800, 600);
InitializeD3D();
InitializeD2D();
InitializeD3DTriangle();
// Run message loop
while (true)
{
// Handle windows messages
MSG msg{};
PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE);
TranslateMessage(&msg);
DispatchMessageW(&msg);
if (msg.message == WM_QUIT)
break;
// Quit is escape is pressed
if (GetAsyncKeyState(VK_ESCAPE) & 0x8000)
break;
// Do frame
Update();
}
return 0;
}
If you want to control the draw order, then you shouldn't be drawing both at the same time. Call Draw, then BeginDraw / EndDraw. Don't mix them as you have no idea when Direct2D is actually flushing commands to the context in your code, and you have no explicit indication of when Direct3D is done drawing to the render target.
You can of course call Direct3D's Flush which will force all work on the GPU to complete, but it's horribly inefficient to call it every frame.
EDIT: Sorry, it's my first time posting here. I've now added the "start_console" files so that you can build it. Sorry for not specifying the problem. My problem is that I expect a triangle to render in the opened window, which it is not.
I've been trying to debug this for a while now but I can't find the problem. Would really appreciate some help :) All the files are posted below except for the eventhandler. I've tried enabling the D3D11_CREATE_DEVICE_DEBUG flag and adding FAILED() functions after each HRESULT but haven't been able to find anything wrong.
main.cpp
//Headers
#define WIN32_LEAN_AND_MEAN
#include "windowCreation.h"
#include "vertex_buffer.h"
#include "shader.h"
#include <comdef.h>
#include "start_console.h"
//hInstance: Used to identify the .exe when it's loaded into memory.
//hPreviousInstance: Always 0.
//pCmdLine: Command-line arguments, convert to argv with CommandLineToArgvW().
//nCmdShow: Flag that says if it should be minimized, maximized or showed normally.
int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine, _In_ int nCmdShow) {
RedirectIOToConsole();
HWND D3D_window = InitWindow(hInstance);
if (D3D_window == NULL) {
return 0;
}
assert(D3D_window);
D3D_create(D3D_window);
Create_Vertex_Buffer();
shader_compile_and_layout();
MSG msg = { };
ShowWindow(D3D_window, nCmdShow);
while (msg.message != WM_QUIT) {
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else {
FLOAT background_color[4] = { 1, 1, 1, 0 };
devcon->ClearRenderTargetView(pView, background_color);
devcon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
devcon->IASetInputLayout(input_layout);
devcon->VSSetShader(vs, NULL, 0);
devcon->PSSetShader(ps, NULL, 0);
devcon->IASetVertexBuffers(0, 1, &Vertex_Buffer, &vertex_strides, &vertex_offset);
devcon->Draw(3, 0);
swapchain->Present(1, 0);
}
}
DestroyWindow(D3D_window);
CleanD3D();
return 0;
}
windowCreation.h
#ifndef WINDOWCREATION_H
#define WINDOWCREATION_H
#include <windows.h> //win32
#include <d3d11.h> //D3D 11
#include <dxgi.h> //Graphics devices and swap chain
#include <assert.h> //for assert()
#include <iostream>
//Libraries
#pragma comment( lib, "user32") //win32
#pragma comment( lib, "gdi32") //Graphics device interface
#pragma comment( lib, "d3d11") //Direct3D 11
#pragma comment( lib, "d3dcompiler.lib") //Shader Compiler
extern unsigned int width;
extern unsigned int height;
extern IDXGISwapChain *swapchain;
extern ID3D11Device *dev;
extern ID3D11DeviceContext *devcon;
extern ID3D11Texture2D* pSwapChainBuffer;
extern ID3D11RenderTargetView* pView;
//Event handler declaration
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
HWND InitWindow(HINSTANCE);
void CleanD3D();
void D3D_create_device_and_swapchain(HWND D3D_window);
void D3D_create_rendertarget();
void D3D_create_rasterizer();
void D3D_create_depth_stencil_state();
void D3D_create_blendstate();
void D3D_create(HWND D3D_window);
#endif
windowCreation.cpp
#include "windowCreation.h"
IDXGISwapChain *swapchain;
ID3D11Device *dev;
ID3D11DeviceContext *devcon;
ID3D11Texture2D* pSwapChainBuffer = 0;
ID3D11RenderTargetView* pView = 0;
unsigned int width = 640;
unsigned int height = 480;
ID3D11RasterizerState *pRSState;
ID3D11DepthStencilState* pDepthStencilState;
ID3D11BlendState* pBlendState;
HWND InitWindow(HINSTANCE hInstance) {
//Declaring the windowclass.
WNDCLASSEX wc = { 0 };
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc; //Pointer to the windowproc-function that handles events.
wc.hInstance = hInstance; //Handle to the application instance.
wc.lpszClassName = L"BasicWindow"; //Identifies the window class
//Registers the window class with the opserating system
if (!RegisterClassEx(&wc)) {
return 0;
}
RECT rc = { 0, 0, width, height };
AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
HWND D3D_window = CreateWindow(
L"BasicWindow",
L"BTH BasicWindow",
WS_OVERLAPPEDWINDOW,
//Size and position
CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top,
nullptr, //Parent window
nullptr, //Menu
hInstance, //Instance handle
nullptr //Additional application data
);
return D3D_window;
}
void D3D_create_device_and_swapchain(HWND D3D_window) {
DXGI_SWAP_CHAIN_DESC scd;
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
scd.BufferCount = 1;
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
scd.OutputWindow = D3D_window;
scd.SampleDesc.Count = 1;
scd.Windowed = TRUE;
D3D11CreateDeviceAndSwapChain(
NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
D3D11_CREATE_DEVICE_DEBUG,
NULL,
NULL,
D3D11_SDK_VERSION,
&scd,
&swapchain,
&dev,
NULL,
&devcon
);
}
void D3D_create_rendertarget() {
HRESULT hr = swapchain->GetBuffer( 0,
__uuidof(ID3D11Texture2D),
(void**)&pSwapChainBuffer);
if (FAILED(hr)) {
std::cout << "fail";
}
hr = dev->CreateRenderTargetView( pSwapChainBuffer,
0,
&pView);
if (FAILED(hr)) {
std::cout << "fail";
}
devcon->OMSetRenderTargets(1, &pView, nullptr);
auto viewport = CD3D11_VIEWPORT(0.0f, 0.0f,
static_cast<float>(width), static_cast<float>(height)
);
devcon->RSSetViewports(1, &viewport);
}
void D3D_create_rasterizer() {
CD3D11_RASTERIZER_DESC desc = {};
desc.FillMode = D3D11_FILL_SOLID;
desc.CullMode = D3D11_CULL_NONE;
HRESULT hr = dev->CreateRasterizerState(&desc, &pRSState);
if (FAILED(hr)) {
std::cout << "fail";
}
devcon->RSGetState(&pRSState);
}
void D3D_create_depth_stencil_state() {
D3D11_DEPTH_STENCIL_DESC desc;
desc.DepthEnable = TRUE;
desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
desc.DepthFunc = D3D11_COMPARISON_LESS;
desc.StencilEnable = FALSE;
desc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
desc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
desc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
desc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
desc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
desc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
desc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
desc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
HRESULT hr = dev->CreateDepthStencilState(&desc, &pDepthStencilState);
devcon->OMSetDepthStencilState(pDepthStencilState, 1);
}
void D3D_create_blendstate() {
D3D11_RENDER_TARGET_BLEND_DESC render_desc;
render_desc.BlendEnable = TRUE;
render_desc.SrcBlend = D3D11_BLEND_ONE;
render_desc.DestBlend = D3D11_BLEND_ZERO;
render_desc.BlendOp = D3D11_BLEND_OP_ADD;
render_desc.SrcBlendAlpha = D3D11_BLEND_ONE;
render_desc.DestBlendAlpha = D3D11_BLEND_ZERO;
render_desc.BlendOpAlpha = D3D11_BLEND_OP_ADD;
render_desc.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
D3D11_BLEND_DESC desc;
desc.AlphaToCoverageEnable = FALSE;
desc.IndependentBlendEnable = FALSE;
desc.RenderTarget[0] = render_desc;
HRESULT hr = dev->CreateBlendState(&desc, &pBlendState);
if (FAILED(hr)) {
std::cout << "fail";
}
devcon->OMSetBlendState(pBlendState, NULL, NULL);
}
void D3D_create(HWND D3D_window) {
D3D_create_device_and_swapchain(D3D_window);
D3D_create_rendertarget();
D3D_create_rasterizer();
D3D_create_depth_stencil_state();
D3D_create_blendstate();
}
void CleanD3D() {
swapchain->Release();
dev->Release();
devcon->Release();
}
vertex_buffer.h
#pragma once
#ifndef VERTEX_BUFFER_H
#define VERTEX_BUFFER_H
#include <vector>
extern struct ID3D11Buffer* Vertex_Buffer;
extern unsigned int vertex_strides;
extern unsigned int vertex_offset;
void Create_Vertex_Buffer();
#endif
vertex_buffer.cpp
#include "vertex_buffer.h"
#include "windowCreation.h"
#include "directxmath.h"
using namespace DirectX;
struct VERTEX {
XMFLOAT3 pos;
XMFLOAT3 col;
};
ID3D11Buffer* Vertex_Buffer;
unsigned int vertex_strides = sizeof(VERTEX);
unsigned int vertex_offset = 0;
void Create_Vertex_Buffer() {
VERTEX vertex_array[] = {
{XMFLOAT3(10, 10, 100), XMFLOAT3(0.0f, 0.0f, 0.0f)},
{XMFLOAT3(100, 10, 100), XMFLOAT3(0.0f, 0.0f, 0.0f)},
{XMFLOAT3(55, 100, 100), XMFLOAT3(0.0f, 0.0f, 0.0f)}
};
D3D11_BUFFER_DESC buffer_struct;
buffer_struct.ByteWidth = sizeof(VERTEX) * 3;
buffer_struct.Usage = D3D11_USAGE_DEFAULT;
buffer_struct.BindFlags = D3D11_BIND_VERTEX_BUFFER;
buffer_struct.CPUAccessFlags = 0;
buffer_struct.MiscFlags = 0;
buffer_struct.StructureByteStride = sizeof(float);
D3D11_SUBRESOURCE_DATA resource_struct;
resource_struct.pSysMem = vertex_array;
resource_struct.SysMemPitch = 0;
resource_struct.SysMemSlicePitch = 0;
HRESULT hr = dev->CreateBuffer(&buffer_struct, &resource_struct, &Vertex_Buffer);
if (FAILED(hr)) {
std::cout << "fail";
}
}
vertex_pixel_shader.hlsl
struct VS_INPUT
{
float3 vColour : COLOR;
float3 vPosition : POSITION;
};
struct VS_OUTPUT
{
float3 vColour : COLOR;
float4 vPosition : SV_POSITION;
};
VS_OUTPUT VSMain(VS_INPUT input)
{
VS_OUTPUT output;
output.vPosition = float4(input.vPosition.xy, 0.0, 1.0);
output.vColour = input.vColour;
return output;
}
float4 PSMain(VS_OUTPUT input) : SV_TARGET
{
return float4(input.vColour, 1.0);
}
shader.h
#pragma once
#ifndef SHADER_H
#define SHADER_H
#include <d3dcompiler.h>
#include <string>
extern struct ID3D11VertexShader* vs;
extern struct ID3D11PixelShader* ps;
extern struct ID3D11InputLayout* input_layout;
void shader_compile_and_layout();
#endif
shader.cpp
#include "shader.h"
#include "windowCreation.h"
ID3DBlob* blob_vs = nullptr;
ID3DBlob* blob_error_vs = nullptr;
ID3DBlob* blob_ps = nullptr;
ID3DBlob* blob_error_ps = nullptr;
ID3D11VertexShader* vs;
ID3D11PixelShader* ps;
ID3D11InputLayout* input_layout;
void shader_compile_and_layout() {
HRESULT hr = D3DCompileFromFile(
L"vertex_pixel_shader.hlsl",
NULL,
NULL,
"VSMain",
"vs_5_0",
0,
0,
&blob_vs,
&blob_error_vs);
if (FAILED(hr)) {
std::cout << "fail";
}
hr = D3DCompileFromFile(
L"vertex_pixel_shader.hlsl",
NULL,
NULL,
"PSMain",
"ps_5_0",
0,
0,
&blob_ps,
&blob_error_ps);
if (FAILED(hr)) {
std::cout << "fail";
}
dev->CreateVertexShader(blob_vs->GetBufferPointer(), blob_vs->GetBufferSize(), NULL, &vs);
dev->CreatePixelShader(blob_ps->GetBufferPointer(), blob_ps->GetBufferSize(), NULL, &ps);
D3D11_INPUT_ELEMENT_DESC input_element_desc[] = {
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0}
};
hr = dev->CreateInputLayout(
input_element_desc, ARRAYSIZE(input_element_desc),
blob_vs->GetBufferPointer(),
blob_vs->GetBufferSize(),
&input_layout
);
if (FAILED(hr)) {
std::cout << "fail";
}
}
start_console.h
#pragma once
#ifndef VERTEX_BUFFER_H
#define VERTEX_BUFFER_H
#include <vector>
extern struct ID3D11Buffer* Vertex_Buffer;
extern unsigned int vertex_strides;
extern unsigned int vertex_offset;
void Create_Vertex_Buffer();
#endif
start_console.cpp
#include "start_console.h"
#include "windowCreation.h"
void RedirectIOToConsole()
{
AllocConsole();
HANDLE stdHandle;
int hConsole;
FILE* fp;
stdHandle = GetStdHandle(STD_OUTPUT_HANDLE);
hConsole = _open_osfhandle((long)stdHandle, _O_TEXT);
fp = _fdopen(hConsole, "w");
freopen_s(&fp, "CONOUT$", "w", stdout);
}
For Direct3D, it's critically important that you set all the relevant state.
I don't see you call OMSetRenderTargets to bind the swapchain to the rendering context via your render target view
devcon->OMSetRenderTarget(1, &pView, nullptr);
I don't see a call to RSSetViewports to set the proper pixel rectangle for rendering.
auto viewport = CD3D11_VIEWPORT(0.0f, 0.0f,
static_cast<float>(backBufferWidth),
static_cast<float>(backBufferHeight)
);
devcon->RSSetViewports(1, &viewport);
You don't appear to be setting a render state object via RSSetState which controls the cull-mode. The default if you don't set it Cull mode set to "back-cull" and FrontCounterClockwise is FALSE. You vertex data could be using the wrong winding and end up backface culled. A good place to start would be to create a object with 'Cull None'.
ID3D11RasterizerState *pRSState;
auto desc = CD3D11_RASTERIZER_DESC
D3D11_RASTERIZER_DESC desc = {};
desc.FillMode = D3D11_FILL_SOLID;
desc.CullMode = D3D11_CULL_NONE;
hr = dev->CreateRasterizerState(&desc, &pRSState);
devcon->RSSetState(pRSState);
Another important state is the blend state via OMSetBlendState. It defaults to an opaque setting.
You don't have a depth buffer, but if you do be sure to set OMSetDepthStencilState.
As you are still getting started, you should probably disable MSAA until you get everything else working.
scd.SampleDesc.Count = 1;
I have complete basic render loops and device templates on GitHub you may want to reference.
You should take a look at DirectX Tool Kit as well.
I'm setting up d3d11 to learn the basics, but I'm having some trouble. I have no errors and everything compiles fine, but ending up with a white window. Am I missing something here? there should be a colored quad in the window. Sorry for any mistakes in asking the question. This is my first post here.
CPP FILE:
#include <Windows.h>
#include <d3d11.h>
#include <d3dcompiler.h>
#include <iostream>
struct Vec3
{
float x, y, z;
};
struct Vertex
{
Vec3 position;
Vec3 color;
};
bool running = true;
HWND hwndApp;
LRESULT CALLBACK AppWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_DESTROY)
{
running = false;
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
int main()
{
WNDCLASSEX appWndClass = { };
appWndClass.lpfnWndProc = AppWndProc;
appWndClass.cbSize = sizeof(WNDCLASSEX);
appWndClass.cbClsExtra = NULL;
appWndClass.cbWndExtra = NULL;
appWndClass.hbrBackground = (HBRUSH)COLOR_WINDOW;
appWndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
appWndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
appWndClass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
appWndClass.style = NULL;
appWndClass.hInstance = GetModuleHandle(NULL);
appWndClass.lpszClassName = "AppWndClass";
appWndClass.lpszMenuName = "";
RegisterClassEx(&appWndClass);
hwndApp = CreateWindowEx(
WS_EX_OVERLAPPEDWINDOW,
appWndClass.lpszClassName,
"AppWndClass",
WS_CAPTION | WS_SYSMENU,
CW_USEDEFAULT, CW_USEDEFAULT, 1024, 768,
NULL,
NULL,
GetModuleHandle(NULL),
NULL
);
ShowWindow(hwndApp, SW_SHOW);
UpdateWindow(hwndApp);
ID3D11Device* d3dDevice = nullptr;
ID3D11DeviceContext* d3dDeviceContext = nullptr;
IDXGIDevice* dxgiDevice = nullptr;
IDXGIAdapter* dxgiAdapter = nullptr;
IDXGIFactory* dxgiFactory = nullptr;
IDXGISwapChain* dxgiSwapChain = nullptr;
ID3D11RenderTargetView* renderTargetView = nullptr;
D3D_FEATURE_LEVEL featureLevel;
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_0
};
D3D11CreateDevice(
nullptr,
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
0,
featureLevels,
ARRAYSIZE(featureLevels),
D3D11_SDK_VERSION,
&d3dDevice,
&featureLevel,
&d3dDeviceContext
);
if (d3dDevice == nullptr) return -1;
if (d3dDeviceContext == nullptr) return -1;
d3dDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)& dxgiDevice);
dxgiDevice->GetAdapter(&dxgiAdapter);
dxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)& dxgiFactory);
RECT rc;
GetClientRect(hwndApp, &rc);
DXGI_SWAP_CHAIN_DESC swapChainDescription;
ZeroMemory(&swapChainDescription, sizeof(swapChainDescription));
swapChainDescription.BufferCount = 1;
swapChainDescription.BufferDesc.Width = rc.right - rc.left;
swapChainDescription.BufferDesc.Height = rc.bottom - rc.top;
swapChainDescription.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDescription.BufferDesc.RefreshRate.Numerator = 60;
swapChainDescription.BufferDesc.RefreshRate.Denominator = 1;
swapChainDescription.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDescription.OutputWindow = hwndApp;
swapChainDescription.SampleDesc.Count = 1;
swapChainDescription.SampleDesc.Quality = 0;
swapChainDescription.Windowed = TRUE;
dxgiFactory->CreateSwapChain(d3dDevice, &swapChainDescription, &dxgiSwapChain);
ID3D11Texture2D* buffer = nullptr;
dxgiSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)& buffer);
if (buffer == nullptr) return -1;
d3dDevice->CreateRenderTargetView(buffer, nullptr, &renderTargetView);
buffer->Release();
if (renderTargetView == nullptr) return -1;
Vertex vertices[] =
{
{ -0.5f, -0.5f, 0.0f, 0, 0, 0 },
{ -0.5f, 0.5f, 0.0f, 1, 1, 0 },
{ 0.5f, -0.5f, 0.0f, 0, 0, 1 },
{ 0.5f, 0.5f, 0.0f, 1, 1, 1 }
};
UINT sizeVertices = ARRAYSIZE(vertices);
D3D11_INPUT_ELEMENT_DESC inputElementDescription[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA , 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }
};
UINT sizeInputElementDescription = ARRAYSIZE(inputElementDescription);
D3D11_BUFFER_DESC bufferDescription = {};
bufferDescription.Usage = D3D11_USAGE_DEFAULT;
bufferDescription.ByteWidth = sizeof(Vertex) * sizeVertices;
bufferDescription.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bufferDescription.CPUAccessFlags = 0;
bufferDescription.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA initialData = {};
initialData.pSysMem = vertices;
ID3D11Buffer* vertexBuffer;
d3dDevice->CreateBuffer(&bufferDescription, &initialData, &vertexBuffer);
void* shaderByteCode = nullptr;
size_t byteCodeLength = 0;
ID3DBlob* blobCode = nullptr;
ID3DBlob* blobErrorMsgs = nullptr;
//D3DCompileFromFile( L"VertexShader.hlsl", nullptr, nullptr, "vsmain", "vs_5_0", 0, 0, &blobCode, &blobErrorMsgs );
if (!SUCCEEDED(D3DCompileFromFile(L"VertexShader.hlsl", nullptr, nullptr, "vsmain", "vs_5_0", 0, 0, &blobCode, &blobErrorMsgs)))
{
if (blobErrorMsgs) blobErrorMsgs->Release();
std::cout << "ERROR COMPILING VERTEXSHADER" << std::endl;
return false;
}
shaderByteCode = blobCode->GetBufferPointer();
byteCodeLength = blobCode->GetBufferSize();
ID3D11VertexShader* vertexShader;
d3dDevice->CreateVertexShader(shaderByteCode, byteCodeLength, nullptr, &vertexShader);
vertexShader->Release();
ID3D11InputLayout* inputLayout;
d3dDevice->CreateInputLayout(inputElementDescription, sizeInputElementDescription, shaderByteCode, byteCodeLength, &inputLayout);
blobCode->Release();
void* shaderByteCode2 = nullptr;
size_t byteCodeLength2 = 0;
ID3DBlob* blobCode2 = nullptr;
ID3DBlob* blobErrorMsgs2 = nullptr;
//D3DCompileFromFile(L"PixelShader.hlsl", nullptr, nullptr, "psmain", "ps_5_0", 0, 0, &blobCode2, &blobErrorMsgs2);
if (!SUCCEEDED(D3DCompileFromFile(L"PixelShader.hlsl", nullptr, nullptr, "psmain", "ps_5_0", 0, 0, &blobCode2, &blobErrorMsgs2)))
{
if (blobErrorMsgs2) blobErrorMsgs2->Release();
std::cout << "ERROR COMPILING PIXELSHADER" << std::endl;
return false;
}
shaderByteCode2 = blobCode2->GetBufferPointer();
byteCodeLength2 = blobCode2->GetBufferSize();
ID3D11PixelShader* pixelShader;
d3dDevice->CreatePixelShader(shaderByteCode2, byteCodeLength2, nullptr, &pixelShader);
pixelShader->Release();
blobCode2->Release();
FLOAT clearColor[] = { 0.0, 0.0, 0.0, 1.0 };
while (running)
{
d3dDeviceContext->ClearRenderTargetView(renderTargetView, clearColor);
d3dDeviceContext->OMSetRenderTargets(1, &renderTargetView, NULL);
GetClientRect(hwndApp, &rc);
D3D11_VIEWPORT vp = {};
vp.Width = rc.right - rc.left;
vp.Height = rc.bottom - rc.top;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
d3dDeviceContext->RSSetViewports(1, &vp);
d3dDeviceContext->VSSetShader(vertexShader, nullptr, 0);
d3dDeviceContext->PSSetShader(pixelShader, nullptr, 0);
UINT stride = sizeof(Vertex);
UINT offset = 0;
d3dDeviceContext->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset);
d3dDeviceContext->IASetInputLayout(inputLayout);
d3dDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
d3dDeviceContext->Draw(sizeVertices, 0);
dxgiSwapChain->Present(true, NULL);
MSG msg = { 0 };
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
renderTargetView->Release();
inputLayout->Release();
vertexBuffer->Release();
dxgiDevice->Release();
dxgiAdapter->Release();
dxgiFactory->Release();
d3dDeviceContext->Release();
d3dDevice->Release();
return 0;
}
VertexShader
struct VS_INPUT
{
float4 position: POSITION;
float3 color: COLOR;
};
struct VS_OUTPUT
{
float4 position: SV_POSITION;
float3 color: COLOR;
};
VS_OUTPUT vsmain(VS_INPUT input)
{
VS_OUTPUT output = (VS_OUTPUT)0;
output.position = input.position;
output.color = input.color;
return output;
}
PixelShader
struct PS_INPUT
{
float4 position: SV_POSITION;
float3 color: COLOR;
};
float4 psmain(PS_INPUT input) : SV_TARGET
{
return float4(input.color,1.0f);
}
I expect the window to show a multicolored quad, but the window is all white.
Shaders was released and then used later in code.
vertexShader->Release();
pixelShader->Release();
moving the release of shaders to the end of the program solved it.
I'm taking my first steps in programming with Direct3D. I have a very basic pipeline setup, and all I want to get from it is an antialiased smooth image. But I get this:
First, I can't get rid of stair effect though I have 4x MSAA enabled already in my pipeline (DXGI_SAMPLE_DESC::Count is 4 and Quality is 0):
And second, I get this noisy texturing though I have mipmaps generated and LINEAR filtering set in the sampler state.
Am I missing something or doing wrong?
Here is my code:
1) Renderer class:
#include "Scene.h" // Custom class that contains vertex and index buffer contents for every rendered mesh.
#include "Camera.h" // Custom class that contains camera position and fov.
#include <wrl/client.h>
using Microsoft::WRL::ComPtr;
#include <DirectXMath.h>
using namespace DirectX;
#include <map>
#include "generated\VertexShader.h"
#include "generated\PixelShader.h"
class Renderer
{
public:
Renderer(HWND hWnd, int wndWidth, int wndHeight, const Scene& scene, const Camera& camera);
void Render();
void SwitchToWireframe();
void SwitchToSolid();
protected:
void CreateDeviceAndSwapChain();
void CreateDepthStencil();
void CreateInputLayout();
void CreateVertexShader();
void CreatePixelShader();
void CreateRasterizerStates();
void CreateBlendState();
void CreateSamplerState();
void CreateBuffer(ID3D11Buffer** buffer,
D3D11_USAGE usage, D3D11_BIND_FLAG bindFlags,
UINT cpuAccessFlags, UINT miscFlags,
UINT sizeOfBuffer, UINT sizeOfBufferElement, const void* initialData);
void CreateTexture2DAndSRV(const Scene::Texture& texture, ID3D11ShaderResourceView** view);
void CreateTexturesAndViews();
void GenerateMips();
protected:
const Scene& m_scene;
const Camera& m_camera;
DWORD m_cameraLastUpdateTickCount;
HWND m_windowHandle;
int m_windowWidth;
int m_windowHeight;
DXGI_SAMPLE_DESC m_sampleDesc;
ComPtr<IDXGISwapChain> m_swapChain;
ComPtr<ID3D11Texture2D> m_swapChainBuffer;
ComPtr<ID3D11RenderTargetView> m_swapChainBufferRTV;
ComPtr<ID3D11Device> m_device;
ComPtr<ID3D11DeviceContext> m_deviceContext;
ComPtr<ID3D11Debug> m_debugger;
ComPtr<ID3D11Texture2D> m_depthStencilTexture;
ComPtr<ID3D11DepthStencilState> m_depthStencilState;
ComPtr<ID3D11DepthStencilView> m_depthStencilView;
ComPtr<ID3D11InputLayout> m_inputLayout;
ComPtr<ID3D11VertexShader> m_vertexShader;
ComPtr<ID3D11PixelShader> m_pixelShader;
ComPtr<ID3D11RasterizerState> m_solidRasterizerState;
ComPtr<ID3D11RasterizerState> m_wireframeRasterizerState;
ComPtr<ID3D11BlendState> m_blendState;
ComPtr<ID3D11SamplerState> m_linearSamplerState;
std::map<std::string, ComPtr<ID3D11ShaderResourceView>> m_diffuseMapViews;
std::map<std::string, ComPtr<ID3D11ShaderResourceView>> m_normalMapViews;
XMMATRIX m_worldViewMatrix;
ID3D11RasterizerState* m_currentRasterizerState;
};
void Renderer::CreateDeviceAndSwapChain()
{
HRESULT hr;
DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
swapChainDesc.BufferDesc.Width = m_windowWidth;
swapChainDesc.BufferDesc.Height = m_windowHeight;
swapChainDesc.BufferDesc.RefreshRate.Numerator = 1;
swapChainDesc.BufferDesc.RefreshRate.Denominator = 60;
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE;
swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_CENTERED;
swapChainDesc.SampleDesc = m_sampleDesc;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.BufferCount = 1;
swapChainDesc.OutputWindow = m_windowHandle;
swapChainDesc.Windowed = TRUE;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
D3D_FEATURE_LEVEL desiredFeatureLevels[] = { D3D_FEATURE_LEVEL_10_1 };
D3D_FEATURE_LEVEL featureLevel;
hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL,
D3D11_CREATE_DEVICE_DEBUG | D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
desiredFeatureLevels, 1, D3D11_SDK_VERSION, &swapChainDesc,
m_swapChain.GetAddressOf(), m_device.GetAddressOf(), &featureLevel,
m_deviceContext.GetAddressOf());
if (FAILED(hr))
{
hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_WARP, NULL,
D3D11_CREATE_DEVICE_DEBUG | D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS,
desiredFeatureLevels, 1, D3D11_SDK_VERSION, &swapChainDesc,
m_swapChain.GetAddressOf(), m_device.GetAddressOf(), &featureLevel,
m_deviceContext.GetAddressOf());
}
if (FAILED(hr))
throw std::exception("Failed to create device or swap chain");
hr = m_device->QueryInterface(m_debugger.GetAddressOf());
if (FAILED(hr))
throw std::exception("Failed to get debugger interface");
hr = m_swapChain->GetBuffer(0, __uuidof(m_swapChainBuffer),
(void**)m_swapChainBuffer.GetAddressOf());
if (FAILED(hr))
throw std::exception("Failed to get swap chain buffer");
hr = m_device->CreateRenderTargetView(m_swapChainBuffer.Get(), NULL,
m_swapChainBufferRTV.GetAddressOf());
if (FAILED(hr))
throw std::exception("Failed to create RTV for swap chain buffer");
}
void Renderer::CreateDepthStencil()
{
HRESULT hr;
D3D11_TEXTURE2D_DESC tdesc;
tdesc.Width = m_windowWidth;
tdesc.Height = m_windowHeight;
tdesc.MipLevels = 1;
tdesc.ArraySize = 1;
tdesc.Format = DXGI_FORMAT_D16_UNORM;
tdesc.SampleDesc = m_sampleDesc;
tdesc.Usage = D3D11_USAGE_DEFAULT;
tdesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
tdesc.CPUAccessFlags = 0;
tdesc.MiscFlags = 0;
hr = m_device->CreateTexture2D(&tdesc, NULL, m_depthStencilTexture.GetAddressOf());
if (FAILED(hr))
throw std::exception("Failed to create depth stencil texture");
D3D11_DEPTH_STENCIL_VIEW_DESC dsvdesc;
dsvdesc.Format = DXGI_FORMAT_D16_UNORM;
dsvdesc.ViewDimension = m_sampleDesc.Count > 1
? D3D11_DSV_DIMENSION_TEXTURE2DMS
: D3D11_DSV_DIMENSION_TEXTURE2D;
dsvdesc.Flags = 0;
dsvdesc.Texture2D.MipSlice = 0;
hr = m_device->CreateDepthStencilView(m_depthStencilTexture.Get(), &dsvdesc,
m_depthStencilView.GetAddressOf());
if (FAILED(hr))
throw std::exception("Failed to create depth stencil view");
D3D11_DEPTH_STENCIL_DESC dsdesc;
dsdesc.DepthEnable = TRUE;
dsdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
dsdesc.DepthFunc = D3D11_COMPARISON_LESS;
dsdesc.StencilEnable = FALSE;
dsdesc.StencilReadMask = 0;
dsdesc.StencilWriteMask = 0;
dsdesc.FrontFace = {};
dsdesc.BackFace = {};
hr = m_device->CreateDepthStencilState(&dsdesc, m_depthStencilState.GetAddressOf());
if (FAILED(hr))
throw std::exception("Failed to create depth stencil state");
}
void Renderer::CreateInputLayout()
{
HRESULT hr;
D3D11_INPUT_ELEMENT_DESC iedescs[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
hr = m_device->CreateInputLayout(iedescs, 3,
g_vertexShader, sizeof(g_vertexShader),
m_inputLayout.GetAddressOf());
if (FAILED(hr))
throw std::exception("Failed to create input layout");
}
void Renderer::CreateVertexShader()
{
HRESULT hr;
hr = m_device->CreateVertexShader(g_vertexShader, sizeof(g_vertexShader),
NULL, m_vertexShader.GetAddressOf());
if (FAILED(hr))
throw std::exception("Failed to create vertex shader");
}
void Renderer::CreatePixelShader()
{
HRESULT hr;
hr = m_device->CreatePixelShader(g_pixelShader, sizeof(g_pixelShader),
NULL, m_pixelShader.GetAddressOf());
if (FAILED(hr))
throw std::exception("Failed to create pixel shader");
}
void Renderer::CreateRasterizerStates()
{
HRESULT hr;
D3D11_RASTERIZER_DESC rdesc;
rdesc.FillMode = D3D11_FILL_SOLID;
rdesc.CullMode = D3D11_CULL_FRONT;
rdesc.FrontCounterClockwise = FALSE;
rdesc.DepthBias = 0;
rdesc.DepthBiasClamp = 0.0f;
rdesc.SlopeScaledDepthBias = 0.0f;
rdesc.DepthClipEnable = TRUE;
rdesc.ScissorEnable = FALSE;
rdesc.MultisampleEnable = m_sampleDesc.Count > 1 ? TRUE : FALSE;
rdesc.AntialiasedLineEnable = m_sampleDesc.Count > 1 ? TRUE : FALSE;
hr = m_device->CreateRasterizerState(&rdesc, m_solidRasterizerState.GetAddressOf());
if (FAILED(hr))
throw std::exception("Failed to create rasterizer state");
rdesc.FillMode = D3D11_FILL_WIREFRAME;
hr = m_device->CreateRasterizerState(&rdesc, m_wireframeRasterizerState.GetAddressOf());
if (FAILED(hr))
throw std::exception("Failed to create rasterizer state");
m_currentRasterizerState = m_solidRasterizerState.Get();
}
void Renderer::CreateSamplerState()
{
HRESULT hr;
D3D11_SAMPLER_DESC smdesc;
smdesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
smdesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
smdesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
smdesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
smdesc.MipLODBias = 0.0f;
smdesc.MaxAnisotropy = 0;
smdesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
smdesc.BorderColor[4] = {};
FLOAT MinLOD = 0.0;
FLOAT MaxLOD = 0.0;
hr = m_device->CreateSamplerState(&smdesc, m_linearSamplerState.GetAddressOf());
if (FAILED(hr))
throw new std::exception("Failed to create sampler state");
}
void Renderer::CreateBlendState()
{
HRESULT hr;
D3D11_BLEND_DESC bdesc;
bdesc.AlphaToCoverageEnable = FALSE;
bdesc.IndependentBlendEnable = FALSE;
bdesc.RenderTarget[0].BlendEnable = FALSE;
bdesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
bdesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO;
bdesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
bdesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
bdesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
bdesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
bdesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
hr = m_device->CreateBlendState(&bdesc, m_blendState.GetAddressOf());
if (FAILED(hr))
throw std::exception("Failed to create blend state");
}
void Renderer::CreateBuffer(ID3D11Buffer** buffer,
D3D11_USAGE usage, D3D11_BIND_FLAG bindFlags,
UINT cpuAccessFlags, UINT miscFlags,
UINT sizeOfBuffer, UINT sizeOfBufferElement, const void* initialData)
{
HRESULT hr;
D3D11_BUFFER_DESC bdesc;
bdesc.ByteWidth = sizeOfBuffer;
bdesc.Usage = usage;
bdesc.BindFlags = bindFlags;
bdesc.CPUAccessFlags = cpuAccessFlags;
bdesc.MiscFlags = miscFlags;
bdesc.StructureByteStride = sizeOfBufferElement;
D3D11_SUBRESOURCE_DATA bdata;
bdata.pSysMem = initialData;
bdata.SysMemPitch = 0;
bdata.SysMemSlicePitch = 0;
hr = m_device->CreateBuffer(&bdesc, &bdata, buffer);
if (FAILED(hr))
throw std::exception("Failed to create buffer");
}
void Renderer::CreateTexture2DAndSRV(const Scene::Texture& sceneTexture, ID3D11ShaderResourceView** view)
{
HRESULT hr;
constexpr DXGI_FORMAT texformat = DXGI_FORMAT_R32G32B32A32_FLOAT;
D3D11_TEXTURE2D_DESC tdesc;
tdesc.Width = sceneTexture.width;
tdesc.Height = sceneTexture.height;
tdesc.MipLevels = 0;
tdesc.ArraySize = 1;
tdesc.Format = texformat;
tdesc.SampleDesc.Count = 1;
tdesc.SampleDesc.Quality = 0;
tdesc.Usage = D3D11_USAGE_DEFAULT;
tdesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
tdesc.CPUAccessFlags = 0;
tdesc.MiscFlags = D3D11_RESOURCE_MISC_GENERATE_MIPS;
ComPtr<ID3D11Texture2D> texture2d;
hr = m_device->CreateTexture2D(&tdesc, NULL, texture2d.GetAddressOf());
if (FAILED(hr))
throw std::exception("Failed to create texture");
D3D11_SUBRESOURCE_DATA srdata;
srdata.pSysMem = sceneTexture.data;
srdata.SysMemPitch = sceneTexture.width * sizeof(float) * 4;
srdata.SysMemSlicePitch = 0;
m_deviceContext->UpdateSubresource(texture2d.Get(), 0, NULL,
srdata.pSysMem, srdata.SysMemPitch, srdata.SysMemSlicePitch);
D3D11_SHADER_RESOURCE_VIEW_DESC srvdesc;
srvdesc.Format = texformat;
srvdesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srvdesc.Texture2D.MostDetailedMip = 0;
srvdesc.Texture2D.MipLevels = -1;
ComPtr<ID3D11ShaderResourceView> shaderResourceView;
hr = m_device->CreateShaderResourceView(texture2d.Get(), &srvdesc, view);
if (FAILED(hr))
throw std::exception("Failed to create shader resource view");
}
void Renderer::CreateTexturesAndViews()
{
for (auto it = m_scene.materials.cbegin(); it != m_scene.materials.cend(); it++)
{
//don't know what's the problem but if I don't place initialized ComPtr<...> instance into a map
//then further .GetAddessOf() fails.
m_diffuseMapViews.emplace(it->first, ComPtr<ID3D11ShaderResourceView>());
m_normalMapViews.emplace(it->first, ComPtr<ID3D11ShaderResourceView>());
CreateTexture2DAndSRV(it->second.diffuseMap, m_diffuseMapViews[it->first].GetAddressOf());
CreateTexture2DAndSRV(it->second.normalMap, m_normalMapViews[it->first].GetAddressOf());
}
}
void Renderer::GenerateMips()
{
for (auto it = m_diffuseMapViews.begin(); it != m_diffuseMapViews.end(); it++)
m_deviceContext->GenerateMips(it->second.Get());
for (auto it = m_normalMapViews.begin(); it != m_normalMapViews.end(); it++)
m_deviceContext->GenerateMips(it->second.Get());
}
Renderer::Renderer(HWND hWnd, int windowWidth, int windowHeight,
const Scene& scene, const Camera& camera)
: m_scene(scene)
, m_camera(camera)
, m_cameraLastUpdateTickCount(0)
, m_windowHandle(hWnd)
, m_windowWidth(windowWidth)
, m_windowHeight(windowHeight)
{
m_sampleDesc.Count = 4;
m_sampleDesc.Quality = 0;
CreateDeviceAndSwapChain();
CreateDepthStencil();
CreateInputLayout();
CreateVertexShader();
CreatePixelShader();
CreateRasterizerStates();
CreateBlendState();
CreateSamplerState();
CreateTexturesAndViews();
GenerateMips();
// Setting up IA stage
m_deviceContext->IASetPrimitiveTopology(
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
m_deviceContext->IASetInputLayout(m_inputLayout.Get());
// Setting up VS stage
m_deviceContext->VSSetShader(m_vertexShader.Get(), 0, 0);
// Setting up RS stage
D3D11_VIEWPORT viewport;
viewport.TopLeftX = 0.0f;
viewport.TopLeftY = 0.0f;
viewport.Width = static_cast<FLOAT>(m_windowWidth);
viewport.Height = static_cast<FLOAT>(m_windowHeight);
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
m_deviceContext->RSSetViewports(1, &viewport);
// Setting up PS stage
m_deviceContext->PSSetSamplers(0, 1, m_linearSamplerState.GetAddressOf());
m_deviceContext->PSSetShader(m_pixelShader.Get(), 0, 0);
// Setting up OM stage
m_deviceContext->OMSetBlendState(m_blendState.Get(), NULL, 0xffffffff);
m_deviceContext->OMSetDepthStencilState(m_depthStencilState.Get(), 0);
m_deviceContext->OMSetRenderTargets(1, m_swapChainBufferRTV.GetAddressOf(), m_depthStencilView.Get());
}
void Renderer::Render()
{
constexpr float background[4] = { 0.047f, 0.0487f, 0.066f, 1.0f };
// Setting up view matix
if (m_cameraLastUpdateTickCount
!= m_camera.GetLastUpdateTickCount())
{
const Float3& camFrom = m_camera.GetFrom();
const Float3& camAt = m_camera.GetAt();
const Float3& camUp = m_camera.GetUp();
m_cameraLastUpdateTickCount = m_camera.GetLastUpdateTickCount();
FXMVECTOR from = XMVectorSet(camFrom.x, camFrom.y, camFrom.z, 1.0f);
FXMVECTOR at = XMVectorSet(camAt.x, camAt.y, camAt.z, 1.0f);
FXMVECTOR up = XMVectorSet(camUp.x, camUp.y, camUp.z, 0.0f);
FXMVECTOR dir = XMVectorSubtract(at, from);
FXMVECTOR x = XMVector3Cross(dir, up);
FXMVECTOR up2 = XMVector3Cross(x, dir);
XMMATRIX lookTo = XMMatrixLookToRH(from, dir, up2);
float scalef = 1.0f / XMVectorGetByIndex(XMVector3Length(dir), 0);
XMMATRIX scale = XMMatrixScaling(scalef, scalef, scalef);
float aspect = float(m_windowWidth) / m_windowHeight;
float fov = m_camera.GetFov() / 180.0f * 3.14f;
XMMATRIX persp = XMMatrixPerspectiveFovRH(fov, aspect, 0.1f, 1000.0f);
m_worldViewMatrix = XMMatrixMultiply(XMMatrixMultiply(lookTo, scale), persp);
}
else
{
return;
}
m_deviceContext->ClearDepthStencilView(m_depthStencilView.Get(), D3D11_CLEAR_DEPTH, 1.0f, 0);
m_deviceContext->ClearRenderTargetView(m_swapChainBufferRTV.Get(), background);
for (auto imesh = m_scene.meshes.cbegin(); imesh != m_scene.meshes.cend(); imesh++)
{
// Creating vertex buffer
ComPtr<ID3D11Buffer> vertexBuffer;
CreateBuffer(vertexBuffer.GetAddressOf(),
D3D11_USAGE_DEFAULT, D3D11_BIND_VERTEX_BUFFER, 0, 0,
sizeof(Scene::Vertex) * imesh->vertices.size(), sizeof(Scene::Vertex),
imesh->vertices.data());
// Creating index buffer
ComPtr<ID3D11Buffer> indexBuffer;
CreateBuffer(indexBuffer.GetAddressOf(),
D3D11_USAGE_DEFAULT, D3D11_BIND_INDEX_BUFFER, 0, 0,
sizeof(unsigned int) * imesh->indices.size(), sizeof(unsigned int),
imesh->indices.data());
// Creating constant buffer
ComPtr<ID3D11Buffer> constantBuffer;
CreateBuffer(constantBuffer.GetAddressOf(),
D3D11_USAGE_IMMUTABLE, D3D11_BIND_CONSTANT_BUFFER, 0, 0,
sizeof(XMMATRIX), sizeof(XMMATRIX),
&m_worldViewMatrix);
// Setting up IA stage
ID3D11Buffer* vertexBuffers[8] = { vertexBuffer.Get() };
unsigned int vertexBufferStrides[8] = { sizeof(Scene::Vertex) };
unsigned int vertexBufferOffsets[8] = { 0 };
m_deviceContext->IASetVertexBuffers(0, 8,
vertexBuffers, vertexBufferStrides, vertexBufferOffsets);
m_deviceContext->IASetIndexBuffer(indexBuffer.Get(), DXGI_FORMAT_R32_UINT, 0);
// Setting up VS stage
m_deviceContext->VSSetConstantBuffers(0, 1, constantBuffer.GetAddressOf());
// Setting up RS stage
m_deviceContext->RSSetState(m_currentRasterizerState);
// Setting up PS stage
ID3D11ShaderResourceView* srvs[2] = { };
srvs[0] = m_diffuseMapViews.at(imesh->material).Get();
srvs[1] = m_normalMapViews.at(imesh->material).Get();
m_deviceContext->PSSetShaderResources(0, 2, srvs);
// Drawing
m_deviceContext->DrawIndexed(imesh->indices.size(), 0, 0);
}
m_swapChain->Present(0, 0);
}
void Renderer::SwitchToWireframe()
{
m_currentRasterizerState = m_wireframeRasterizerState.Get();
m_camera.UpdateLastUpdateTickCount();
}
void Renderer::SwitchToSolid()
{
m_currentRasterizerState = m_solidRasterizerState.Get();
m_camera.UpdateLastUpdateTickCount();
}
2) Vertex shader
struct VS_INPUT
{
float3 position : POSITION;
float3 normal : NORMAL;
float2 texcoord : TEXCOORD;
};
struct VS_OUTPUT
{
float4 position : SV_POSITION;
float3 normal : NORMAL;
float2 texcoord : TEXCOORD;
};
cbuffer Matrices
{
matrix worldViewMatrix;
}
VS_OUTPUT main(VS_INPUT input)
{
VS_OUTPUT output;
output.position = mul(worldViewMatrix, float4(input.position.xyz, 1.0));
output.normal = input.normal;
output.texcoord = input.texcoord;
return output;
}
3) Pixel shader
Texture2D DiffuseMap : register(t0);
Texture2D NormalMap: register(t1);
SamplerState LinearSampler : register(s0);
float4 main(VS_OUTPUT input) : SV_TARGET
{
float3 light = normalize(float3(2.87, -0.36, 1.68));
float3 diffuseColor = DiffuseMap.Sample(LinearSampler, input.texcoord);
float3 normalDisplace = float3(0.0, 0.0, 1.0) - NormalMap.Sample(LinearSampler, input.texcoord);
float illumination = clamp(dot(light, input.normal + normalDisplace), 0.2, 1.0);
return float4(mul(diffuseColor, illumination), 1.0);
}
Okay, I've just figured out the reason of this stairs effect:
The reason is that I passed the same width and height values for CreateWindow WinApi function, and for DXGI_SWAP_CHAIN_DESC::BufferDesc. Meanwhile, these should be different because CreateWindow takes outer width and height of a window to create (window rectangle), while BufferDesc should receive inner values (window client area rectangle). Because of that actual area on screen was smaller than swap chain buffer and the result of rendering was presumably resampled to fit the rectangle, which was introducing the aliasing after MSAA was already applied.
Fixing the issue gave a much cleaner result (4x MSAA is applied here):
But the question with texture aliasing is still open:
I can initialize win32 window and directx11 fine, but when i try to draw triangle window appears and then it freezes my pc so i have to reboot it.
Here is my WinMain code:
#include "DXApp.h"
#include<DirectXMath.h>
class App : public DXApp {
public:
App(HINSTANCE hInstance);
~App();
bool Init() override;
void Update(float dt) override;
void Render(float dt) override;
};
int WINAPI WinMain(__in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in LPSTR lpCmdLine, __in int nShowCmd) {
App app(hInstance);
if (!app.Init()) return 1;
return app.Run();
}
App::App(HINSTANCE hInstance) : DXApp(hInstance)
{
}
App::~App()
{
}
bool App::Init()
{
return DXApp::Init();
}
void App::Update(float dt)
{
}
void App::Render(float dt)
{
immediateContext->ClearRenderTargetView(renderTargetView, DirectX::Colors::CornflowerBlue);
immediateContext->Draw(3, 0);
swapChain->Present(0, 0);
}
And my app header and cpp:
DXApp.h:
#pragma once
#include<Windows.h>
#include<string>
#include"DXUtil.h"
#include<d3dcompiler.h>
#pragma comment(lib, "d3dcompiler.lib")
#define WIN32_LEAN_AND_MEAN
class DXApp
{
public:
DXApp(HINSTANCE hInstance);
void cleanUp();
virtual ~DXApp(void);
//MAIN APPLICATION LOOP
int Run();
//FRAMEWORK METHODS
virtual bool Init();
virtual void Update(float dt) = 0;
virtual void Render(float dt) = 0;
virtual LRESULT MsgProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam);
protected:
HWND hAppWnd;
HINSTANCE hAppInstance;
unsigned int ClientWidth;
unsigned int ClientHeight;
std::string AppTitle;
DWORD WindStyle;
//DIRECTX ATTRIBUTES
ID3D11Device* device;
ID3D11DeviceContext* immediateContext;
IDXGISwapChain* swapChain;
ID3D11RenderTargetView* renderTargetView;
D3D_DRIVER_TYPE driverType;
D3D_FEATURE_LEVEL featureLevel;
D3D11_VIEWPORT viewport;
ID3D11Buffer* triangleVertBuffer;
ID3D11PixelShader* pixelShader;
ID3D11VertexShader* vertexShader;
ID3D10Blob* VSBuffer;
ID3D10Blob* PSBuffer;
ID3D11InputLayout* vertLayout;
protected:
//INITIALZE WIN32 WINDOW
bool windowInit();
//INITIALIZE DIRECTX
bool direct3dInit();
};
DXApp.cpp:
#include "DXApp.h"
namespace {
DXApp * g_pApp = nullptr;
}
LRESULT CALLBACK MainWndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam) {
if (g_pApp) return g_pApp->MsgProc(hwnd, msg, wParam, lParam);
else return DefWindowProc(hwnd, msg, wParam, lParam);
}
//VERTEX
struct Vertex {
Vertex() {}
Vertex(float x, float y, float z) : pos(x, y, z) {}
DirectX::XMFLOAT3 pos;
};
D3D11_INPUT_ELEMENT_DESC layout[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
unsigned int numLayoutElements = ARRAYSIZE(layout);
DXApp::DXApp(HINSTANCE hInstance)
{
hAppInstance = hInstance;
hAppWnd = NULL;
ClientWidth = 1280;
ClientHeight = 720;
AppTitle = "DirectX11 Engine";
WindStyle = WS_OVERLAPPEDWINDOW;
g_pApp = this;
//DIRECTX
device = nullptr;
swapChain = nullptr;
immediateContext = nullptr;
renderTargetView = nullptr;
vertexShader = nullptr;
pixelShader = nullptr;
triangleVertBuffer = nullptr;
VSBuffer = nullptr;
PSBuffer = nullptr;
vertLayout = nullptr;
}
void DXApp::cleanUp()
{
if (immediateContext) immediateContext->ClearState();
Memory::SafeRelease(renderTargetView);
Memory::SafeRelease(immediateContext);
Memory::SafeRelease(swapChain);
Memory::SafeRelease(device);
Memory::SafeRelease(vertLayout);
Memory::SafeRelease(PSBuffer);
Memory::SafeRelease(VSBuffer);
Memory::SafeRelease(triangleVertBuffer);
Memory::SafeRelease(pixelShader);
Memory::SafeRelease(vertexShader);
}
DXApp::~DXApp()
{
//DIRECTX CLEANUP
if (immediateContext) immediateContext->ClearState();
Memory::SafeRelease(renderTargetView);
Memory::SafeRelease(immediateContext);
Memory::SafeRelease(swapChain);
Memory::SafeRelease(device);
Memory::SafeRelease(vertLayout);
Memory::SafeRelease(PSBuffer);
Memory::SafeRelease(VSBuffer);
Memory::SafeRelease(triangleVertBuffer);
Memory::SafeRelease(pixelShader);
Memory::SafeRelease(vertexShader);
}
int DXApp::Run() {
MSG msg = { 0 };
while (WM_QUIT != msg.message) {
if (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else {
Update(0.0f);
Render(0.0f);
}
}
return static_cast<int>(msg.wParam);
}
bool DXApp::Init()
{
if (!windowInit()) {
return false;
}
if (!direct3dInit()) {
return false;
}
return true;
}
bool DXApp::windowInit()
{
WNDCLASSEX wcex;
ZeroMemory(&wcex, sizeof(WNDCLASSEX));
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.hInstance = hAppInstance;
wcex.lpfnWndProc = MainWndProc;
wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = "DXAPPWNDCLASS";
wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wcex)) {
OutputDebugString("\nFAILED TO CREATE WINDOW CLASS!!\n");
return false;
}
RECT r = { 0, 0, ClientWidth, ClientHeight };
AdjustWindowRect(&r, WindStyle, false);
unsigned int width = r.right - r.left;
unsigned int height = r.bottom - r.top;
unsigned int x = GetSystemMetrics(SM_CXSCREEN) / 2 - width / 2;
unsigned int y = GetSystemMetrics(SM_CYSCREEN) / 2 - height / 2;
hAppWnd = CreateWindow("DXAPPWNDCLASS", AppTitle.c_str(), WindStyle, x, y, width, height, NULL, NULL, hAppInstance, NULL);
if (!hAppWnd) {
OutputDebugString("\nFAILED TO CREATE WINDOW!!\n");
return false;
}
ShowWindow(hAppWnd, SW_SHOW);
return true;
}
//DIRECTX INITIALIZATION
bool DXApp::direct3dInit()
{
unsigned int createDeviceFlags = 0;
#ifdef DEBUG
createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif // DEBUG
D3D_DRIVER_TYPE driverTypes[] = {
D3D_DRIVER_TYPE_HARDWARE,
D3D_DRIVER_TYPE_WARP,
D3D_DRIVER_TYPE_REFERENCE
};
unsigned int numDriverTypes = ARRAYSIZE(driverTypes);
D3D_FEATURE_LEVEL featureLevels[] = {
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_3
};
unsigned int numFeatureLevels = ARRAYSIZE(featureLevels);
DXGI_SWAP_CHAIN_DESC swapDesc;
ZeroMemory(&swapDesc, sizeof(DXGI_SWAP_CHAIN_DESC));
swapDesc.BufferCount = 1;
swapDesc.BufferDesc.Width = ClientWidth;
swapDesc.BufferDesc.Height = ClientHeight;
swapDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapDesc.BufferDesc.RefreshRate.Numerator = 60;
swapDesc.BufferDesc.RefreshRate.Denominator = 1;
swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapDesc.OutputWindow = hAppWnd;
swapDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapDesc.Windowed = true;
swapDesc.SampleDesc.Count = 1;
swapDesc.SampleDesc.Quality = 0;
swapDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
HRESULT result;
for (int i = 0; i < numDriverTypes; ++i) {
result = D3D11CreateDeviceAndSwapChain(NULL, driverTypes[i], NULL, createDeviceFlags, featureLevels, numFeatureLevels,
D3D11_SDK_VERSION, &swapDesc, &swapChain, &device, &featureLevel, &immediateContext);
if (SUCCEEDED(result)) {
driverType = driverTypes[i];
break;
}
if (FAILED(result)) {
OutputDebugString("FAILED TO CREATE DX11 DEVICE!!");
return false;
}
}
//RENDER TARGET VIEW
ID3D11Texture2D* backBufferTex = 0;
swapChain->GetBuffer(NULL, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&backBufferTex));
device->CreateRenderTargetView(backBufferTex, nullptr, &renderTargetView);
//BIND RENDER TARGET VIEW
immediateContext->OMSetRenderTargets(1, &renderTargetView, nullptr);
//COMPILE SHADERS FROM FILE
result = D3DCompileFromFile(L"VertexShader.hlsl", 0, 0, "vertexShader", "vs_4_0", 0, 0, &VSBuffer, &VSBuffer);
result = D3DCompileFromFile(L"PixelShader.hlsl", 0, 0, "pixelShader", "ps_4_0", 0, 0, &PSBuffer, &PSBuffer);
//CREATE SHADER OBJECTS
result = device->CreateVertexShader(VSBuffer->GetBufferPointer(), VSBuffer->GetBufferSize(), 0, &vertexShader);
result = device->CreatePixelShader(PSBuffer->GetBufferPointer(), PSBuffer->GetBufferSize(), 0, &pixelShader);
//SET SHADERS
immediateContext->VSSetShader(vertexShader, 0, 0);
immediateContext->PSSetShader(pixelShader, 0, 0);
//CREATE VERTEX BUFFER
Vertex v[] = {
Vertex(0.0f, 0.5f, 0.5f),
Vertex(0.5f, -0.5f, 0.5f),
Vertex(-0.5f, 0.5f, 0.5f),
};
D3D11_BUFFER_DESC vertexBufferDesc;
ZeroMemory(&vertexBufferDesc, sizeof(D3D11_BUFFER_DESC));
vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
vertexBufferDesc.ByteWidth = sizeof(Vertex) * 3;
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexBufferDesc.CPUAccessFlags = 0;
vertexBufferDesc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA vertexBufferData;
ZeroMemory(&vertexBufferData, sizeof(vertexBufferData));
vertexBufferData.pSysMem = v;
result = device->CreateBuffer(&vertexBufferDesc, &vertexBufferData, &triangleVertBuffer);
//SET VERTEX BUFFER
unsigned int stride = sizeof(Vertex);
unsigned int offset = 0;
immediateContext->IAGetVertexBuffers(0, 1, &triangleVertBuffer, &stride, &offset);
//CREATE INPUT LAYOUT
device->CreateInputLayout(layout, numLayoutElements, VSBuffer->GetBufferPointer(), VSBuffer->GetBufferSize(), &vertLayout);
//SET INPUT LAYOUT
immediateContext->IASetInputLayout(vertLayout);
//SET PRIMITIVE TOPOLOGY
immediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
//VIEWPORT CREATION
ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
viewport.Width = static_cast<float>(ClientWidth);
viewport.Height = static_cast<float>(ClientHeight);
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
//SET VIEWPORT
immediateContext->RSSetViewports(1, &viewport);
return true;
}
//MESSAGES
LRESULT DXApp::MsgProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
}
The first steps in debugging a Direct3D program are:
Make sure you are properly checking all HRESULT values. There are numerous places in your code where you are failing to check the result. If the Direct3D function returns a void, you can ignore error checking. Otherwise you need to use SUCCEEDED, FAILED, or use something like ThrowIfFailed. This is essentially because continuing beyond a failure is going to make it very hard to debug the true cause of the problem.
Enable the Direct3D debug device and look for output. You appear to have that in your debug builds. Do you see any output in the debug window?
It is highly unusual to have a program 'hang' your system, but it is possible if you have a bad driver or faulty hardware. Without more details, however, it's difficult to diagnose since your program is faulty to begin with.