1
0
Files
xplayer/nanovg/nanovg_d3d11.h
2023-10-19 15:03:27 +08:00

1566 lines
48 KiB
C

//
// Copyright (c) 2009-2013 Mikko Mononen memon@inside.org
// Port of _gl.h to _d3d11.h by Chris Maughan
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
//
#ifndef NANOVG_D3D11_H
#define NANOVG_D3D11_H
// Hide nameless struct/union warning for D3D headers
#ifdef _MSC_VER
#pragma warning (disable : 4201)
#endif
#include <d3d11.h>
#ifdef _MSC_VER
#pragma warning (default : 4201)
#endif
#ifdef __cplusplus
extern "C" {
#endif
// Flag indicating if geoemtry based anti-aliasing is used (may not be needed when using MSAA).
#define NVG_ANTIALIAS 1
// Flag indicating if strokes should be drawn using stencil buffer. The rendering will be a little
// slower, but path overlaps (i.e. self-intersecting or sharp turns) will be drawn just once.
#define NVG_STENCIL_STROKES 2
struct NVGcontext* nvgCreateD3D11(ID3D11Device* pDevice, int edgeaa);
void nvgDeleteD3D11(struct NVGcontext* ctx);
// These are additional flags on top of NVGimageFlags.
enum NVGimageFlagsD3D11 {
NVG_IMAGE_NODELETE = 1<<16, // Do not delete texture object.
};
// Not done yet. Simple enough to do though...
#ifdef IMPLEMENTED_IMAGE_FUNCS
int nvd3dCreateImageFromHandle(struct NVGcontext* ctx, void* texture, int w, int h, int flags);
unsigned int nvd3dImageHandle(struct NVGcontext* ctx, int image);
void nvd3dImageFlags(struct NVGcontext* ctx, int image, int flags);
#endif
#ifdef __cplusplus
}
#endif
#ifdef NANOVG_D3D11_IMPLEMENTATION
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include "nanovg.h"
#include <d3d11.h>
#include "nvg_shader/D3D11VertexShader.h"
#include "nvg_shader/D3D11PixelShaderAA.h"
#include "nvg_shader/D3D11PixelShader.h"
// The cpp calling is much simpler.
// For 'c' calling of DX, we need to do pPtr->lpVtbl->Func(pPtr, ...)
// There's probably a better way... (but note we can't use the IInterace_Method() helpers because
// They won't work when compiled for cpp)
#ifdef __cplusplus
#define D3D_API(p, name, arg1) p->name()
#define D3D_API_1(p, name, arg1) p->name(arg1)
#define D3D_API_2(p, name, arg1, arg2) p->name(arg1, arg2)
#define D3D_API_3(p, name, arg1, arg2, arg3) p->name(arg1, arg2, arg3)
#define D3D_API_4(p, name, arg1, arg2, arg3, arg4) p->name(arg1, arg2, arg3, arg4)
#define D3D_API_5(p, name, arg1, arg2, arg3, arg4, arg5) p->name(arg1, arg2, arg3, arg4, arg5)
#define D3D_API_6(p, name, arg1, arg2, arg3, arg4, arg5, arg6) p->name(arg1, arg2, arg3, arg4, arg5, arg6)
#define D3D_API_7(p, name, arg1, arg2, arg3, arg4, arg5, arg6, arg7) p->name(arg1, arg2, arg3, arg4, arg5, arg6, arg7)
#define D3D_API_8(p, name, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) p->name(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
#define D3D_API_RELEASE(p) { if ( (p) ) { (p)->Release(); (p) = NULL; } }
#else
#define D3D_API(p, name) p->lpVtbl->name(p)
#define D3D_API_1(p, name, arg1) p->lpVtbl->name(p, arg1)
#define D3D_API_2(p, name, arg1, arg2) p->lpVtbl->name(p, arg1, arg2)
#define D3D_API_3(p, name, arg1, arg2, arg3) p->lpVtbl->name(p, arg1, arg2, arg3)
#define D3D_API_4(p, name, arg1, arg2, arg3, arg4) p->lpVtbl->name(p, arg1, arg2, arg3, arg4)
#define D3D_API_5(p, name, arg1, arg2, arg3, arg4, arg5) p->lpVtbl->name(p, arg1, arg2, arg3, arg4, arg5)
#define D3D_API_6(p, name, arg1, arg2, arg3, arg4, arg5, arg6) p->lpVtbl->name(p, arg1, arg2, arg3, arg4, arg5, arg6)
#define D3D_API_7(p, name, arg1, arg2, arg3, arg4, arg5, arg6, arg7) p->lpVtbl->name(p, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
#define D3D_API_8(p, name, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) p->lpVtbl->name(p, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
#define D3D_API_RELEASE(p) { if ( (p) ) { (p)->lpVtbl->Release((p)); (p) = NULL; } }
#endif
#pragma pack(push)
#pragma pack(16)
struct D3DNVGfragUniforms
{
float scissorMat[16];
float scissorExt[4];
float scissorScale[4];
float paintMat[16];
float extent[4];
float radius[4];
float feather[4];
struct NVGcolor innerCol;
struct NVGcolor outerCol;
float strokeMult[4];
int texType;
int type;
};
#pragma pack(pop)
struct VS_CONSTANTS
{
float dummy[16];
float viewSize[2];
};
enum D3DNVGshaderType {
NSVG_SHADER_FILLGRAD,
NSVG_SHADER_FILLIMG,
NSVG_SHADER_SIMPLE,
NSVG_SHADER_IMG
};
struct D3DNVGshader {
ID3D11PixelShader* frag;
ID3D11VertexShader* vert;
struct VS_CONSTANTS vc;
};
struct D3DNVGtexture {
int id;
ID3D11Texture2D* tex;
ID3D11Texture2D* stagingTex;
ID3D11ShaderResourceView* resourceView;
int width, height;
int type;
int flags;
};
enum D3DNVGcallType {
D3DNVG_NONE = 0,
D3DNVG_FILL,
D3DNVG_CONVEXFILL,
D3DNVG_STROKE,
D3DNVG_TRIANGLES
};
struct D3DNVGcall {
int type;
int image;
int pathOffset;
int pathCount;
int triangleOffset;
int triangleCount;
int uniformOffset;
};
struct D3DNVGpath {
int fillOffset;
int fillCount;
int strokeOffset;
int strokeCount;
};
struct D3DNVGBuffer {
unsigned int MaxBufferEntries;
unsigned int CurrentBufferEntry;
ID3D11Buffer* pBuffer;
};
struct D3DNVGcontext {
struct D3DNVGshader shader;
struct D3DNVGtexture* textures;
float view[2];
int ntextures;
int ctextures;
int textureId;
ID3D11SamplerState* pSamplerState[4];
int fragSize;
int flags;
// Per frame buffers
struct D3DNVGcall* calls;
int ccalls;
int ncalls;
struct D3DNVGpath* paths;
int cpaths;
int npaths;
struct NVGvertex* verts;
int cverts;
int nverts;
unsigned char* uniforms;
int cuniforms;
int nuniforms;
// D3D
// Geometry
struct D3DNVGBuffer VertexBuffer;
ID3D11Buffer* pFanIndexBuffer;
ID3D11InputLayout* pLayoutRenderTriangles;
// State
ID3D11Buffer* pVSConstants;
ID3D11Buffer* pPSConstants;
ID3D11Device* pDevice;
ID3D11DeviceContext* pDeviceContext;
ID3D11BlendState* pBSBlend;
ID3D11BlendState* pBSNoWrite;
ID3D11RasterizerState* pRSNoCull;
ID3D11RasterizerState* pRSCull;
ID3D11DepthStencilState* pDepthStencilDrawShapes;
ID3D11DepthStencilState* pDepthStencilDrawAA;
ID3D11DepthStencilState* pDepthStencilFill;
ID3D11DepthStencilState* pDepthStencilDefault;
};
static int D3Dnvg__maxi(int a, int b) { return a > b ? a : b; }
static struct D3DNVGtexture* D3Dnvg__allocTexture(struct D3DNVGcontext* D3D)
{
struct D3DNVGtexture* tex = NULL;
int i;
for (i = 0; i < D3D->ntextures; i++) {
if (D3D->textures[i].id == 0) {
tex = &D3D->textures[i];
break;
}
}
if (tex == NULL) {
if (D3D->ntextures + 1 > D3D->ctextures) {
struct D3DNVGtexture* textures;
int ctextures = D3Dnvg__maxi(D3D->ntextures+1, 4) + D3D->ctextures/2; // 1.5x Overallocate
textures = (struct D3DNVGtexture*)realloc(D3D->textures, sizeof(struct D3DNVGtexture)*ctextures);
if (textures == NULL) return NULL;
D3D->textures = textures;
D3D->ctextures = ctextures;
}
tex = &D3D->textures[D3D->ntextures++];
}
memset(tex, 0, sizeof(*tex));
tex->id = ++D3D->textureId;
return tex;
}
static struct D3DNVGtexture* D3Dnvg__findTexture(struct D3DNVGcontext* D3D, int id)
{
int i;
for (i = 0; i < D3D->ntextures; i++)
if (D3D->textures[i].id == id)
return &D3D->textures[i];
return NULL;
}
static int D3Dnvg__deleteTexture(struct D3DNVGcontext* D3D, int id)
{
int i;
for (i = 0; i < D3D->ntextures; i++) {
if (D3D->textures[i].id == id) {
if (D3D->textures[i].tex != 0 && (D3D->textures[i].flags & NVG_IMAGE_NODELETE) == 0)
{
D3D_API_RELEASE(D3D->textures[i].tex);
D3D_API_RELEASE(D3D->textures[i].resourceView);
if (D3D->textures[i].stagingTex != NULL) {
D3D_API_RELEASE(D3D->textures[i].stagingTex);
D3D->textures[i].stagingTex = NULL;
}
}
memset(&D3D->textures[i], 0, sizeof(D3D->textures[i]));
return 1;
}
}
return 0;
}
// BEGIN D3D specific
static void D3Dnvg_copyMatrix3to4(float* pDest, const float* pSource)
{
unsigned int i;
for (i = 0; i < 4; i++)
{
memcpy(&pDest[i * 4], &pSource[i * 3], sizeof(float) * 3);
}
}
// END D3D specific
static int D3Dnvg__checkError(HRESULT hr, const char* str)
{
if (!SUCCEEDED(hr))
{
printf("Error %08lx after %s\n", hr, str);
return 1;
}
return 0;
}
static int D3Dnvg__createShader(struct D3DNVGcontext* D3D, struct D3DNVGshader* shader, const void* vshader, unsigned int vshader_size, const void* fshader, unsigned int fshader_size)
{
ID3D11VertexShader* vert = NULL;
ID3D11PixelShader* frag = NULL;
HRESULT hr;
memset(shader, 0, sizeof(*shader));
// Shader byte code is created at compile time from the .hlsl files.
// No need for error checks; shader errors can be fixed in the IDE.
hr = D3D_API_4(D3D->pDevice, CreateVertexShader, vshader, vshader_size, NULL, &vert);
if (hr != S_OK) return 0;
hr = D3D_API_4(D3D->pDevice, CreatePixelShader, fshader, fshader_size, NULL, &frag);
if (hr != S_OK) return 0;
shader->vert = vert;
shader->frag = frag;
return SUCCEEDED(hr) ? 1 : -1;
}
static void D3Dnvg__deleteShader(struct D3DNVGshader* shader)
{
D3D_API_RELEASE(shader->vert);
D3D_API_RELEASE(shader->frag);
}
void D3Dnvg_buildFanIndices(struct D3DNVGcontext* D3D)
{
UINT32 index0 = 0;
UINT32 index1 = 1;
UINT32 index2 = 2;
UINT32 current = 0;
D3D11_MAPPED_SUBRESOURCE resource;
UINT32* pIndices = NULL;
D3D_API_5(D3D->pDeviceContext, Map, (ID3D11Resource*)D3D->pFanIndexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource);
pIndices = (UINT32*)resource.pData;
while (current < (D3D->VertexBuffer.MaxBufferEntries - 3))
{
pIndices[current++] = index0;
pIndices[current++] = index1++;
pIndices[current++] = index2++;
}
D3D_API_2(D3D->pDeviceContext, Unmap, (ID3D11Resource*)D3D->pFanIndexBuffer, 0);
}
struct NVGvertex* D3Dnvg_beginVertexBuffer(struct D3DNVGcontext* D3D, unsigned int maxCount, unsigned int* baseOffset)
{
D3D11_MAPPED_SUBRESOURCE resource;
if (maxCount >= D3D->VertexBuffer.MaxBufferEntries)
{
D3Dnvg__checkError(E_FAIL, "Vertex buffer too small!");
return NULL;
}
if ((D3D->VertexBuffer.CurrentBufferEntry + maxCount) >= D3D->VertexBuffer.MaxBufferEntries)
{
*baseOffset = 0;
D3D->VertexBuffer.CurrentBufferEntry = maxCount;
D3D_API_5(D3D->pDeviceContext, Map, (ID3D11Resource*)D3D->VertexBuffer.pBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource);
}
else
{
*baseOffset = D3D->VertexBuffer.CurrentBufferEntry;
D3D->VertexBuffer.CurrentBufferEntry = *baseOffset + maxCount;
D3D_API_5(D3D->pDeviceContext, Map, (ID3D11Resource*)D3D->VertexBuffer.pBuffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &resource);
}
return ((struct NVGvertex*)resource.pData + *baseOffset);
}
void D3Dnvg_endVertexBuffer(struct D3DNVGcontext* D3D)
{
D3D_API_2(D3D->pDeviceContext, Unmap, (ID3D11Resource*)D3D->VertexBuffer.pBuffer, 0);
}
static void D3Dnvg__copyVerts(struct NVGvertex* pDest, const struct NVGvertex* pSource, unsigned int num)
{
unsigned int i;
for (i = 0; i < num; i++)
{
pDest[i].x = pSource[i].x;
pDest[i].y = pSource[i].y;
pDest[i].u = pSource[i].u;
pDest[i].v = pSource[i].v;
}
}
static unsigned int D3Dnvg_updateVertexBuffer(ID3D11DeviceContext* pContext, struct D3DNVGBuffer* buffer, const struct NVGvertex* verts, unsigned int nverts)
{
D3D11_MAPPED_SUBRESOURCE resource;
unsigned int retEntry;
if (nverts > buffer->MaxBufferEntries)
{
D3Dnvg__checkError(E_FAIL, "Vertex buffer too small!");
return 0;
}
if ((buffer->CurrentBufferEntry + nverts) >= buffer->MaxBufferEntries)
{
buffer->CurrentBufferEntry = 0;
D3D_API_5(pContext, Map, (ID3D11Resource*)buffer->pBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &resource);
}
else
{
D3D_API_5(pContext, Map, (ID3D11Resource*)buffer->pBuffer, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &resource);
}
D3Dnvg__copyVerts((((struct NVGvertex*)resource.pData) + buffer->CurrentBufferEntry), (const struct NVGvertex*)verts, nverts);
D3D_API_2(pContext, Unmap, (ID3D11Resource*)buffer->pBuffer, 0);
retEntry = buffer->CurrentBufferEntry;
buffer->CurrentBufferEntry += nverts;
return retEntry;
}
static void D3Dnvg_setBuffers(struct D3DNVGcontext* D3D, unsigned int dynamicOffset)
{
ID3D11Buffer* pBuffers[1];
unsigned int strides[1];
unsigned int offsets[1];
pBuffers[0] = D3D->VertexBuffer.pBuffer;
strides[0] = sizeof(struct NVGvertex);
offsets[0] = dynamicOffset * sizeof(struct NVGvertex);
D3D_API_3(D3D->pDeviceContext, IASetIndexBuffer, D3D->pFanIndexBuffer, DXGI_FORMAT_R32_UINT, 0);
D3D_API_5(D3D->pDeviceContext, IASetVertexBuffers, 0, 1, pBuffers, strides, offsets);
D3D_API_1(D3D->pDeviceContext, IASetInputLayout, D3D->pLayoutRenderTriangles);
}
static int D3Dnvg__renderCreate(void* uptr)
{
HRESULT hr;
D3D11_BUFFER_DESC bufferDesc;
D3D11_RASTERIZER_DESC rasterDesc;
D3D11_BLEND_DESC blendDesc;
D3D11_DEPTH_STENCIL_DESC depthStencilDesc;
D3D11_SAMPLER_DESC sampDesc;
struct D3DNVGcontext* D3D = (struct D3DNVGcontext*)uptr;
const D3D11_DEPTH_STENCILOP_DESC frontOp = { D3D11_STENCIL_OP_KEEP, D3D11_STENCIL_OP_KEEP, D3D11_STENCIL_OP_INCR, D3D11_COMPARISON_ALWAYS };
const D3D11_DEPTH_STENCILOP_DESC backOp = { D3D11_STENCIL_OP_KEEP, D3D11_STENCIL_OP_KEEP, D3D11_STENCIL_OP_DECR, D3D11_COMPARISON_ALWAYS };
const D3D11_DEPTH_STENCILOP_DESC aaOp = { D3D11_STENCIL_OP_KEEP, D3D11_STENCIL_OP_KEEP, D3D11_STENCIL_OP_KEEP, D3D11_COMPARISON_EQUAL };
const D3D11_DEPTH_STENCILOP_DESC fillOp = { D3D11_STENCIL_OP_ZERO, D3D11_STENCIL_OP_ZERO, D3D11_STENCIL_OP_ZERO, D3D11_COMPARISON_NOT_EQUAL };
const D3D11_DEPTH_STENCILOP_DESC defaultOp = { D3D11_STENCIL_OP_KEEP, D3D11_STENCIL_OP_KEEP, D3D11_STENCIL_OP_KEEP, D3D11_COMPARISON_ALWAYS };
D3D11_INPUT_ELEMENT_DESC LayoutRenderTriangles[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0 }
};
if (D3D->flags & NVG_ANTIALIAS) {
if (D3Dnvg__createShader(D3D, &D3D->shader, g_D3D11VertexShader_Main, sizeof(g_D3D11VertexShader_Main), g_D3D11PixelShaderAA_Main, sizeof(g_D3D11PixelShaderAA_Main)) == 0)
return 0;
}
else {
if (D3Dnvg__createShader(D3D, &D3D->shader, g_D3D11VertexShader_Main, sizeof(g_D3D11VertexShader_Main), g_D3D11PixelShader_Main, sizeof(g_D3D11PixelShader_Main)) == 0)
return 0;
}
// Todo: Need to find a good value for this, and
// Use the dynamic buffer fill technnique to handle overflow
D3D->VertexBuffer.MaxBufferEntries = 1000000;
D3D->VertexBuffer.CurrentBufferEntry = 0;
memset(&bufferDesc, 0, sizeof(bufferDesc));
bufferDesc.Usage = D3D11_USAGE_DYNAMIC;
bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
bufferDesc.MiscFlags = 0;
// Create the vertex buffer.
bufferDesc.ByteWidth = sizeof(struct NVGvertex)* D3D->VertexBuffer.MaxBufferEntries;
hr = D3D_API_3(D3D->pDevice, CreateBuffer, &bufferDesc, NULL, &D3D->VertexBuffer.pBuffer);
D3Dnvg__checkError(hr, "Create Vertex Buffer");
bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
bufferDesc.ByteWidth = sizeof(UINT32)* D3D->VertexBuffer.MaxBufferEntries;
hr = D3D_API_3(D3D->pDevice, CreateBuffer, &bufferDesc, NULL, &D3D->pFanIndexBuffer);
D3Dnvg__checkError(hr, "Create Vertex Buffer Static");
D3Dnvg_buildFanIndices(D3D);
hr = D3D_API_5(D3D->pDevice, CreateInputLayout, LayoutRenderTriangles, 2, g_D3D11VertexShader_Main, sizeof(g_D3D11VertexShader_Main), &D3D->pLayoutRenderTriangles);
D3Dnvg__checkError(hr, "Create Input Layout");
bufferDesc.Usage = D3D11_USAGE_DYNAMIC;
bufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
bufferDesc.MiscFlags = 0;
bufferDesc.ByteWidth = sizeof(struct VS_CONSTANTS);
if ((bufferDesc.ByteWidth % 16) != 0)
{
bufferDesc.ByteWidth += 16 - (bufferDesc.ByteWidth % 16);
}
hr = D3D_API_3(D3D->pDevice, CreateBuffer, &bufferDesc, NULL, &D3D->pVSConstants);
D3Dnvg__checkError(hr, "Create Constant Buffer");
bufferDesc.ByteWidth = sizeof(struct D3DNVGfragUniforms);
if ((bufferDesc.ByteWidth % 16) != 0)
{
bufferDesc.ByteWidth += 16 - (bufferDesc.ByteWidth % 16);
}
D3D->fragSize = bufferDesc.ByteWidth;
hr = D3D_API_3(D3D->pDevice, CreateBuffer, &bufferDesc, NULL, &D3D->pPSConstants);
D3Dnvg__checkError(hr, "Create Constant Buffer");
ZeroMemory(&rasterDesc, sizeof(rasterDesc));
rasterDesc.FillMode = D3D11_FILL_SOLID;
rasterDesc.CullMode = D3D11_CULL_NONE;
rasterDesc.DepthClipEnable = TRUE;
rasterDesc.FrontCounterClockwise = TRUE;
hr = D3D_API_2(D3D->pDevice, CreateRasterizerState, &rasterDesc, &D3D->pRSNoCull);
rasterDesc.CullMode = D3D11_CULL_BACK;
hr = D3D_API_2(D3D->pDevice, CreateRasterizerState, &rasterDesc, &D3D->pRSCull);
ZeroMemory(&blendDesc, sizeof(blendDesc));
blendDesc.RenderTarget[0].BlendEnable = TRUE;
blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE;
blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
blendDesc.IndependentBlendEnable = FALSE;
hr = D3D_API_2(D3D->pDevice, CreateBlendState, &blendDesc, &D3D->pBSBlend);
blendDesc.RenderTarget[0].BlendEnable = FALSE;
blendDesc.RenderTarget[0].RenderTargetWriteMask = 0;
hr = D3D_API_2(D3D->pDevice, CreateBlendState, &blendDesc, &D3D->pBSNoWrite);
// Stencil A Draw shapes
ZeroMemory(&depthStencilDesc, sizeof(depthStencilDesc));
depthStencilDesc.DepthEnable = FALSE;
depthStencilDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL;
depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
depthStencilDesc.StencilEnable = TRUE;
depthStencilDesc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
depthStencilDesc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
depthStencilDesc.FrontFace = frontOp;
depthStencilDesc.BackFace = backOp;
// No color write
hr = D3D_API_2(D3D->pDevice, CreateDepthStencilState, &depthStencilDesc, &D3D->pDepthStencilDrawShapes);
// Draw AA
depthStencilDesc.FrontFace = aaOp;
depthStencilDesc.BackFace = aaOp;
hr = D3D_API_2(D3D->pDevice, CreateDepthStencilState, &depthStencilDesc, &D3D->pDepthStencilDrawAA);
// Stencil Fill
depthStencilDesc.FrontFace = fillOp;
depthStencilDesc.BackFace = fillOp;
hr = D3D_API_2(D3D->pDevice, CreateDepthStencilState, &depthStencilDesc, &D3D->pDepthStencilFill);
depthStencilDesc.FrontFace = defaultOp;
depthStencilDesc.BackFace = defaultOp;
depthStencilDesc.StencilEnable = FALSE;
hr = D3D_API_2(D3D->pDevice, CreateDepthStencilState, &depthStencilDesc, &D3D->pDepthStencilDefault);
ZeroMemory(&sampDesc, sizeof(sampDesc));
sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
sampDesc.MinLOD = 0;
sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
sampDesc.MipLODBias = 0.0f;//-1.0f;
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
D3D_API_2(D3D->pDevice, CreateSamplerState, &sampDesc, &D3D->pSamplerState[0]);
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
D3D_API_2(D3D->pDevice, CreateSamplerState, &sampDesc, &D3D->pSamplerState[1]);
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
D3D_API_2(D3D->pDevice, CreateSamplerState, &sampDesc, &D3D->pSamplerState[2]);
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
D3D_API_2(D3D->pDevice, CreateSamplerState, &sampDesc, &D3D->pSamplerState[3]);
return 1;
}
static int D3Dnvg__renderCreateTexture(void* uptr, int type, int w, int h, int imageFlags, const unsigned char* data)
{
struct D3DNVGcontext* D3D = (struct D3DNVGcontext*)uptr;
struct D3DNVGtexture* tex = D3Dnvg__allocTexture(D3D);
D3D11_TEXTURE2D_DESC texDesc;
int pixelWidthBytes;
HRESULT hr;
D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc;
if (tex == NULL)
{
return 0;
}
tex->width = w;
tex->height = h;
tex->type = type;
tex->flags = imageFlags;
memset(&texDesc, 0, sizeof(texDesc));
texDesc.ArraySize = 1;
texDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
texDesc.CPUAccessFlags = 0;
texDesc.MipLevels = 1;
if (type == NVG_TEXTURE_RGBA) {
texDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
pixelWidthBytes = 4;
// Mip maps
if (imageFlags & NVG_IMAGE_GENERATE_MIPMAPS)
{
texDesc.MipLevels = 0;
texDesc.BindFlags |= D3D11_BIND_RENDER_TARGET;
texDesc.MiscFlags = D3D11_RESOURCE_MISC_GENERATE_MIPS;
}
} else {
texDesc.Format = DXGI_FORMAT_R8_UNORM;
pixelWidthBytes = 1;
texDesc.MipLevels = 1;
}
texDesc.Height = tex->height;
texDesc.Width = tex->width;
texDesc.SampleDesc.Count = 1;
texDesc.SampleDesc.Quality = 0;
if (imageFlags & NVG_IMAGE_STREAMING) {
texDesc.Usage = D3D11_USAGE_DYNAMIC;
texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
} else {
texDesc.Usage = D3D11_USAGE_DEFAULT;
}
hr = D3D_API_3(D3D->pDevice, CreateTexture2D, &texDesc, NULL, &tex->tex);
if (FAILED(hr))
{
return 0;
}
if (data != NULL)
{
D3D_API_6(D3D->pDeviceContext, UpdateSubresource, (ID3D11Resource*)tex->tex, 0, NULL, data, tex->width * pixelWidthBytes, (tex->width * tex->height) * pixelWidthBytes);
}
viewDesc.Format = texDesc.Format;
viewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
viewDesc.Texture2D.MipLevels = texDesc.MipLevels;
viewDesc.Texture2D.MostDetailedMip = 0;
D3D_API_3(D3D->pDevice, CreateShaderResourceView, (ID3D11Resource*)tex->tex, &viewDesc, &tex->resourceView);
if (data != NULL && texDesc.MipLevels == 0)
{
D3D_API_1(D3D->pDeviceContext, GenerateMips, tex->resourceView);
}
if (D3Dnvg__checkError(hr, "create tex"))
return 0;
return tex->id;
}
static int D3Dnvg__renderDeleteTexture(void* uptr, int image)
{
struct D3DNVGcontext* D3D = (struct D3DNVGcontext*)uptr;
return D3Dnvg__deleteTexture(D3D, image);
}
static int D3Dnvg__renderUpdateTexture(void* uptr, int image, int x, int y, int w, int h, const unsigned char* data)
{
struct D3DNVGcontext* D3D = (struct D3DNVGcontext*)uptr;
struct D3DNVGtexture* tex = D3Dnvg__findTexture(D3D, image);
D3D11_BOX box;
unsigned int pixelWidthBytes;
unsigned char* pData;
if (tex == NULL)
{
return 0;
}
box.left = x;
box.right = (x + w);
box.top = y;
box.bottom = (y + h);
box.front = 0;
box.back = 1;
if (tex->type == NVG_TEXTURE_RGBA)
{
pixelWidthBytes = 4;
}
else
{
pixelWidthBytes = 1;
}
if (tex->flags & NVG_IMAGE_COPY_SWAP) {
ID3D11Texture2D *stagingTexture;
D3D11_TEXTURE2D_DESC stagingTextureDesc;
D3D11_MAPPED_SUBRESOURCE textureMemory;
HRESULT hr;
const unsigned char *src;
unsigned char *dst;
// 缓存临时 texture
if (tex->stagingTex) {
stagingTexture = tex->stagingTex;
} else {
D3D_API_1(tex->tex, GetDesc, &stagingTextureDesc);
stagingTextureDesc.Width = w;
stagingTextureDesc.Height = h;
stagingTextureDesc.BindFlags = 0;
stagingTextureDesc.MiscFlags = 0;
stagingTextureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
stagingTextureDesc.Usage = D3D11_USAGE_STAGING;
hr = D3D_API_3(D3D->pDevice, CreateTexture2D, &stagingTextureDesc, NULL, &stagingTexture);
if (FAILED(hr)) {
return 0;
}
tex->stagingTex = stagingTexture;
}
hr = D3D_API_5(D3D->pDeviceContext, Map, (ID3D11Resource*)stagingTexture, 0, D3D11_MAP_WRITE, 0, &textureMemory);
if (FAILED(hr)) {
return 0;
}
unsigned int length = w * pixelWidthBytes;
unsigned int pitch = length;
src = (const unsigned char *)data;
dst = (unsigned char *)textureMemory.pData;
if (length == textureMemory.RowPitch) {
memcpy(dst, src, length*h);
} else {
if (length > textureMemory.RowPitch) {
length = textureMemory.RowPitch;
}
int row;
for (row = 0; row < h; ++row) {
memcpy(dst, src, length);
src += pitch;
dst += textureMemory.RowPitch;
}
}
D3D_API_2(D3D->pDeviceContext, Unmap, (ID3D11Resource*)stagingTexture, 0);
D3D_API_8(D3D->pDeviceContext, CopySubresourceRegion, (ID3D11Resource *)tex->tex, 0, x, y, 0, (ID3D11Resource *)stagingTexture, 0, NULL);
} else {
pData = (unsigned char*)data + (y * (tex->width * pixelWidthBytes)) + (x * pixelWidthBytes);
D3D_API_6(D3D->pDeviceContext, UpdateSubresource, (ID3D11Resource*)tex->tex, 0, &box, pData, tex->width, tex->width * tex->height);
}
return 1;
}
static int D3Dnvg__renderGetTextureSize(void* uptr, int image, int* w, int* h)
{
struct D3DNVGcontext* D3D = (struct D3DNVGcontext*)uptr;
struct D3DNVGtexture* tex = D3Dnvg__findTexture(D3D, image);
if (tex == NULL)
{
return 0;
}
*w = tex->width;
*h = tex->height;
return 1;
}
static void D3Dnvg__xformToMat3x3(float* m3, float* t)
{
m3[0] = t[0];
m3[1] = t[1];
m3[2] = 0.0f;
m3[3] = t[2];
m3[4] = t[3];
m3[5] = 0.0f;
m3[6] = t[4];
m3[7] = t[5];
m3[8] = 1.0f;
}
static struct NVGcolor D3Dnvg__premulColor(struct NVGcolor c)
{
c.r *= c.a;
c.g *= c.a;
c.b *= c.a;
return c;
}
static int D3Dnvg__convertPaint(struct D3DNVGcontext* D3D, struct D3DNVGfragUniforms* frag,
struct NVGpaint* paint, struct NVGscissor* scissor,
float width, float fringe, float strokeThr)
{
struct D3DNVGtexture* tex = NULL;
float invxform[6], paintMat[9], scissorMat[9];
memset(frag, 0, sizeof(*frag));
frag->innerCol = D3Dnvg__premulColor(paint->innerColor);
frag->outerCol = D3Dnvg__premulColor(paint->outerColor);
if (scissor->extent[0] < -0.5f || scissor->extent[1] < -0.5f)
{
memset(scissorMat, 0, sizeof(scissorMat));
frag->scissorExt[0] = 1.0f;
frag->scissorExt[1] = 1.0f;
frag->scissorScale[0] = 1.0f;
frag->scissorScale[1] = 1.0f;
}
else
{
nvgTransformInverse(invxform, scissor->xform);
D3Dnvg__xformToMat3x3(scissorMat, invxform);
frag->scissorExt[0] = scissor->extent[0];
frag->scissorExt[1] = scissor->extent[1];
frag->scissorScale[0] = sqrtf(scissor->xform[0] * scissor->xform[0] + scissor->xform[2] * scissor->xform[2]) / fringe;
frag->scissorScale[1] = sqrtf(scissor->xform[1] * scissor->xform[1] + scissor->xform[3] * scissor->xform[3]) / fringe;
}
D3Dnvg_copyMatrix3to4(frag->scissorMat, scissorMat);
frag->extent[0] = paint->extent[0];
frag->extent[1] = paint->extent[1];
frag->strokeMult[0] = (width*0.5f + fringe*0.5f) / fringe;
frag->strokeMult[1] = strokeThr;
if (paint->image != 0)
{
tex = D3Dnvg__findTexture(D3D, paint->image);
if (tex == NULL)
{
return 0;
}
if ((tex->flags & NVG_IMAGE_FLIPY) != 0)
{
float m1[6], m2[6];
nvgTransformTranslate(m1, 0.0f, frag->extent[1] * 0.5f);
nvgTransformMultiply(m1, paint->xform);
nvgTransformScale(m2, 1.0f, -1.0f);
nvgTransformMultiply(m2, m1);
nvgTransformTranslate(m1, 0.0f, -frag->extent[1] * 0.5f);
nvgTransformMultiply(m1, m2);
nvgTransformInverse(invxform, m1);
}
else
{
nvgTransformInverse(invxform, paint->xform);
}
frag->type = NSVG_SHADER_FILLIMG;
#if NANOVG_GL_USE_UNIFORMBUFFER
if (tex->type == NVG_TEXTURE_RGBA)
{
frag->texType = (tex->flags & NVG_IMAGE_PREMULTIPLIED) ? 0 : 1;
}
else
{
frag->texType = 2;
}
#else
if (tex->type == NVG_TEXTURE_RGBA)
frag->texType = (tex->flags & NVG_IMAGE_PREMULTIPLIED) ? 0.0f : 1.0f;
else
frag->texType = 2.0f;
#endif
}
else
{
frag->type = NSVG_SHADER_FILLGRAD;
frag->radius[0] = paint->radius;
frag->feather[0] = paint->feather;
nvgTransformInverse(invxform, paint->xform);
}
D3Dnvg__xformToMat3x3(paintMat, invxform);
D3Dnvg_copyMatrix3to4(frag->paintMat, paintMat);
//D3Dnvg_updateShaders(D3D);
return 1;
}
static struct D3DNVGfragUniforms* nvg__fragUniformPtr(struct D3DNVGcontext* D3D, int i);
static void D3Dnvg__setUniforms(struct D3DNVGcontext* D3D, int uniformOffset, int image)
{
struct D3DNVGfragUniforms* frag = nvg__fragUniformPtr(D3D, uniformOffset);
D3D11_MAPPED_SUBRESOURCE MappedResource;
// Pixel shader constants
D3D_API_5(D3D->pDeviceContext, Map, (ID3D11Resource*)D3D->pPSConstants, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedResource);
memcpy(MappedResource.pData, frag, sizeof(struct D3DNVGfragUniforms));
D3D_API_2(D3D->pDeviceContext, Unmap, (ID3D11Resource*)D3D->pPSConstants, 0);
if (image != 0)
{
struct D3DNVGtexture* tex = D3Dnvg__findTexture(D3D, image);
if (tex != NULL)
{
D3D_API_3(D3D->pDeviceContext, PSSetShaderResources,0, 1, &tex->resourceView);
}
else
{
// D3D_API_3(D3D->pDeviceContext, PSSetShaderResources,0, 1, NULL);
}
}
else
{
// D3D_API_3(D3D->pDeviceContext, PSSetShaderResources,0, 1, NULL);
}
}
static void D3Dnvg__renderViewport(void* uptr, float width, float height, float devicePixelRatio)
{
NVG_NOTUSED(devicePixelRatio);
struct D3DNVGcontext* D3D = (struct D3DNVGcontext*)uptr;
D3D11_MAPPED_SUBRESOURCE mappedResource;
//D3D->alphaMode = alphaBlend;
D3D->shader.vc.viewSize[0] = width;
D3D->shader.vc.viewSize[1] = height;
// Vertex parameters only change when viewport size changes
D3D_API_5(D3D->pDeviceContext, Map, (ID3D11Resource*)D3D->pVSConstants, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
memcpy(mappedResource.pData, &D3D->shader.vc, sizeof(struct VS_CONSTANTS));
D3D_API_2(D3D->pDeviceContext, Unmap, (ID3D11Resource*)D3D->pVSConstants, 0);
}
static void D3Dnvg__fill(struct D3DNVGcontext* D3D, struct D3DNVGcall* call)
{
struct D3DNVGpath* paths = &D3D->paths[call->pathOffset];
int i, npaths = call->pathCount;
// Draw shapes
D3D_API_2(D3D->pDeviceContext, OMSetDepthStencilState, D3D->pDepthStencilDrawShapes, 0);
D3D_API_3(D3D->pDeviceContext, OMSetBlendState, D3D->pBSNoWrite, NULL, 0xFFFFFFFF);
D3D_API_1(D3D->pDeviceContext, RSSetState, D3D->pRSNoCull);
// set bindpoint for solid loc
D3Dnvg__setUniforms(D3D, call->uniformOffset, 0);
D3D_API_1(D3D->pDeviceContext, IASetPrimitiveTopology, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
for (i = 0; i < npaths; i++)
{
unsigned int numIndices = ((paths[i].fillCount - 2) * 3);
assert(numIndices < D3D->VertexBuffer.MaxBufferEntries);
if (numIndices < D3D->VertexBuffer.MaxBufferEntries)
{
D3D_API_3(D3D->pDeviceContext, DrawIndexed, numIndices, 0, paths[i].fillOffset);
}
}
// Draw anti-aliased pixels
D3D_API_1(D3D->pDeviceContext, RSSetState, D3D->pRSCull);
D3D_API_1(D3D->pDeviceContext, IASetPrimitiveTopology, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
D3D_API_3(D3D->pDeviceContext, OMSetBlendState, D3D->pBSBlend, NULL, 0xFFFFFFFF);
D3Dnvg__setUniforms(D3D, call->uniformOffset + D3D->fragSize, call->image);
if (D3D->flags & NVG_ANTIALIAS)
{
D3D_API_2(D3D->pDeviceContext, OMSetDepthStencilState, D3D->pDepthStencilDrawAA, 0);
// Draw fringes
for (i = 0; i < npaths; i++)
{
D3D_API_2(D3D->pDeviceContext, Draw, paths[i].strokeCount, paths[i].strokeOffset);
}
}
// Draw fill
D3D_API_1(D3D->pDeviceContext, RSSetState, D3D->pRSNoCull);
D3D_API_2(D3D->pDeviceContext, OMSetDepthStencilState, D3D->pDepthStencilFill, 0);
D3D_API_2(D3D->pDeviceContext, Draw, call->triangleCount, call->triangleOffset);
D3D_API_2(D3D->pDeviceContext, OMSetDepthStencilState, D3D->pDepthStencilDefault, 0);
}
static void D3Dnvg__convexFill(struct D3DNVGcontext* D3D, struct D3DNVGcall* call)
{
struct D3DNVGpath* paths = &D3D->paths[call->pathOffset];
int i, npaths = call->pathCount;
D3Dnvg__setUniforms(D3D, call->uniformOffset, call->image);
D3D_API_1(D3D->pDeviceContext, IASetPrimitiveTopology, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
for (i = 0; i < npaths; i++)
{
// Draws a fan using indices to fake it up, since there isn't a fan primitive in D3D11.
if (paths[i].fillCount > 2)
{
unsigned int numIndices = ((paths[i].fillCount - 2) * 3);
assert(numIndices < D3D->VertexBuffer.MaxBufferEntries);
if (numIndices < D3D->VertexBuffer.MaxBufferEntries)
{
D3D_API_3(D3D->pDeviceContext, DrawIndexed, numIndices, 0, paths[i].fillOffset);
}
}
}
// Draw fringes
D3D_API_1(D3D->pDeviceContext, IASetPrimitiveTopology, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
for (i = 0; i < npaths; i++)
{
if (paths[i].strokeCount > 0) {
D3D_API_2(D3D->pDeviceContext, Draw, paths[i].strokeCount, paths[i].strokeOffset);
}
}
}
static void D3Dnvg__stroke(struct D3DNVGcontext* D3D, struct D3DNVGcall* call)
{
struct D3DNVGpath* paths = &D3D->paths[call->pathOffset];
int npaths = call->pathCount, i;
D3D_API_1(D3D->pDeviceContext, IASetPrimitiveTopology, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
if (D3D->flags & NVG_STENCIL_STROKES)
{
// Fill the stroke base without overlap
D3D_API_2(D3D->pDeviceContext, OMSetDepthStencilState, D3D->pDepthStencilDefault, 0);
D3Dnvg__setUniforms(D3D, call->uniformOffset + D3D->fragSize, call->image);
for (i = 0; i < npaths; i++)
{
D3D_API_2(D3D->pDeviceContext, Draw, paths[i].strokeCount, paths[i].strokeOffset);
}
// Draw anti-aliased pixels.
D3Dnvg__setUniforms(D3D, call->uniformOffset, call->image);
D3D_API_2(D3D->pDeviceContext, OMSetDepthStencilState, D3D->pDepthStencilDrawAA, 0);
for (i = 0; i < npaths; i++)
{
D3D_API_2(D3D->pDeviceContext, Draw, paths[i].strokeCount, paths[i].strokeOffset);
}
// Clear stencil buffer.
D3D_API_2(D3D->pDeviceContext, OMSetDepthStencilState, D3D->pDepthStencilFill, 0);
for (i = 0; i < npaths; i++)
{
D3D_API_2(D3D->pDeviceContext, Draw, paths[i].strokeCount, paths[i].strokeOffset);
}
D3D_API_2(D3D->pDeviceContext, OMSetDepthStencilState, D3D->pDepthStencilDefault, 0);
}
else
{
D3Dnvg__setUniforms(D3D, call->uniformOffset, call->image);
// Draw Strokes
for (i = 0; i < npaths; i++)
{
D3D_API_2(D3D->pDeviceContext, Draw, paths[i].strokeCount, paths[i].strokeOffset);
}
}
}
static void D3Dnvg__triangles(struct D3DNVGcontext* D3D, struct D3DNVGcall* call)
{
D3D_API_1(D3D->pDeviceContext, IASetPrimitiveTopology, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
D3Dnvg__setUniforms(D3D, call->uniformOffset, call->image);
D3D_API_2(D3D->pDeviceContext, Draw, call->triangleCount, call->triangleOffset);
}
static void D3Dnvg__renderCancel(void* uptr)
{
struct D3DNVGcontext* D3D = (struct D3DNVGcontext*)uptr;
D3D->nverts = 0;
D3D->npaths = 0;
D3D->ncalls = 0;
D3D->nuniforms = 0;
}
static void D3Dnvg__renderFlush(void* uptr)
{
struct D3DNVGcontext* D3D = (struct D3DNVGcontext*)uptr;
int i;
if (D3D->ncalls > 0)
{
unsigned int buffer0Offset = D3Dnvg_updateVertexBuffer(D3D->pDeviceContext, &D3D->VertexBuffer, D3D->verts, D3D->nverts);
D3Dnvg_setBuffers(D3D, buffer0Offset);
// Ensure valid state
D3D_API_3(D3D->pDeviceContext, PSSetConstantBuffers, 0, 1, &D3D->pPSConstants);
D3D_API_3(D3D->pDeviceContext, VSSetConstantBuffers, 0, 1, &D3D->pVSConstants);
D3D_API_3(D3D->pDeviceContext, PSSetShader, D3D->shader.frag, NULL, 0);
D3D_API_3(D3D->pDeviceContext, VSSetShader, D3D->shader.vert, NULL, 0);
// Draw shapes
D3D_API_2(D3D->pDeviceContext, OMSetDepthStencilState, D3D->pDepthStencilDefault, 0);
D3D_API_3(D3D->pDeviceContext, OMSetBlendState, D3D->pBSBlend, NULL, 0xFFFFFFFF);
D3D_API_1(D3D->pDeviceContext, RSSetState, D3D->pRSCull);
for (i = 0; i < D3D->ncalls; i++) {
struct D3DNVGcall* call = &D3D->calls[i];
if (call->image != 0)
{
struct D3DNVGtexture* tex = D3Dnvg__findTexture(D3D, call->image);
if (tex != NULL)
{
D3D_API_3(D3D->pDeviceContext, PSSetSamplers, 0, 1, &D3D->pSamplerState[(tex->flags & NVG_IMAGE_REPEATX ? 1 : 0) + (tex->flags & NVG_IMAGE_REPEATY ? 2 : 0)]);
}
}
if (call->type == D3DNVG_FILL)
D3Dnvg__fill(D3D, call);
else if (call->type == D3DNVG_CONVEXFILL)
D3Dnvg__convexFill(D3D, call);
else if (call->type == D3DNVG_STROKE)
D3Dnvg__stroke(D3D, call);
else if (call->type == D3DNVG_TRIANGLES)
D3Dnvg__triangles(D3D, call);
}
}
// Reset calls
D3D->nverts = 0;
D3D->npaths = 0;
D3D->ncalls = 0;
D3D->nuniforms = 0;
}
static int D3Dnvg__maxVertCount(const struct NVGpath* paths, int npaths)
{
int i, count = 0;
for (i = 0; i < npaths; i++) {
count += paths[i].nfill;
count += paths[i].nstroke;
}
return count;
}
static struct D3DNVGcall* D3Dnvg__allocCall(struct D3DNVGcontext* D3D)
{
struct D3DNVGcall* ret = NULL;
if (D3D->ncalls+1 > D3D->ccalls) {
struct D3DNVGcall* calls;
int ccalls = D3Dnvg__maxi(D3D->ncalls+1, 128) + D3D->ccalls/2; // 1.5x Overallocate
calls = (struct D3DNVGcall*)realloc(D3D->calls, sizeof(struct D3DNVGcall) * ccalls);
if (calls == NULL) return NULL;
D3D->calls = calls;
D3D->ccalls = ccalls;
}
ret = &D3D->calls[D3D->ncalls++];
memset(ret, 0, sizeof(struct D3DNVGcall));
return ret;
}
static int D3Dnvg__allocPaths(struct D3DNVGcontext* D3D, int n)
{
int ret = 0;
if (D3D->npaths+n > D3D->cpaths) {
struct D3DNVGpath* paths;
int cpaths = D3Dnvg__maxi(D3D->npaths + n, 128) + D3D->cpaths/2; // 1.5x Overallocate
paths = (struct D3DNVGpath*)realloc(D3D->paths, sizeof(struct D3DNVGpath) * cpaths);
if (paths == NULL) return -1;
D3D->paths = paths;
D3D->cpaths = cpaths;
}
ret = D3D->npaths;
D3D->npaths += n;
return ret;
}
static int D3Dnvg__allocVerts(struct D3DNVGcontext* D3D, int n)
{
int ret = 0;
if (D3D->nverts+n > D3D->cverts) {
struct NVGvertex* verts;
int cverts = D3Dnvg__maxi(D3D->nverts + n, 4096) + D3D->cverts/2; // 1.5x Overallocate
verts = (struct NVGvertex*)realloc(D3D->verts, sizeof(struct NVGvertex) * cverts);
if (verts == NULL) return -1;
D3D->verts = verts;
D3D->cverts = cverts;
}
ret = D3D->nverts;
D3D->nverts += n;
return ret;
}
static int D3Dnvg__allocFragUniforms(struct D3DNVGcontext* D3D, int n)
{
int ret = 0, structSize = D3D->fragSize;
if (D3D->nuniforms+n > D3D->cuniforms) {
unsigned char* uniforms;
int cuniforms = D3Dnvg__maxi(D3D->nuniforms+n, 128) + D3D->cuniforms/2; // 1.5x Overallocate
uniforms = (unsigned char*)realloc(D3D->uniforms, structSize * cuniforms);
if (uniforms == NULL) return -1;
D3D->uniforms = uniforms;
D3D->cuniforms = cuniforms;
}
ret = D3D->nuniforms * structSize;
D3D->nuniforms += n;
return ret;
}
static struct D3DNVGfragUniforms* nvg__fragUniformPtr(struct D3DNVGcontext* D3D, int i)
{
return (struct D3DNVGfragUniforms*)&D3D->uniforms[i];
}
static void D3Dnvg__vset(struct NVGvertex* vtx, float x, float y, float u, float v)
{
vtx->x = x;
vtx->y = y;
vtx->u = u;
vtx->v = v;
}
static void D3Dnvg__renderFill(void* uptr, struct NVGpaint* paint, NVGcompositeOperationState compositeOperation, struct NVGscissor* scissor, float fringe,
const float* bounds, const struct NVGpath* paths, int npaths)
{
struct D3DNVGcontext* D3D = (struct D3DNVGcontext*)uptr;
struct D3DNVGcall* call = D3Dnvg__allocCall(D3D);
struct NVGvertex* quad;
struct D3DNVGfragUniforms* frag;
int i, maxverts, offset;
if (call == NULL) return;
call->type = D3DNVG_FILL;
call->triangleCount = 4;
call->pathOffset = D3Dnvg__allocPaths(D3D, npaths);
if (call->pathOffset == -1) goto error;
call->pathCount = npaths;
call->image = paint->image;
NVG_NOTUSED(compositeOperation);
if (npaths == 1 && paths[0].convex)
{
call->type = D3DNVG_CONVEXFILL;
call->triangleCount = 0; // Bounding box fill quad not needed for convex fill
}
// Allocate vertices for all the paths.
maxverts = D3Dnvg__maxVertCount(paths, npaths) + call->triangleCount;
offset = D3Dnvg__allocVerts(D3D, maxverts);
if (offset == -1) goto error;
for (i = 0; i < npaths; i++) {
struct D3DNVGpath* copy = &D3D->paths[call->pathOffset + i];
const struct NVGpath* path = &paths[i];
memset(copy, 0, sizeof(struct D3DNVGpath));
if (path->nfill > 0) {
copy->fillOffset = offset;
copy->fillCount = path->nfill;
memcpy(&D3D->verts[offset], path->fill, sizeof(struct NVGvertex) * path->nfill);
offset += path->nfill;
}
if (path->nstroke > 0) {
copy->strokeOffset = offset;
copy->strokeCount = path->nstroke;
memcpy(&D3D->verts[offset], path->stroke, sizeof(struct NVGvertex) * path->nstroke);
offset += path->nstroke;
}
}
if (call->type == D3DNVG_FILL) {
// Quad
call->triangleOffset = offset;
quad = &D3D->verts[call->triangleOffset];
D3Dnvg__vset(&quad[0], bounds[2], bounds[3], 0.5f, 1.0f);
D3Dnvg__vset(&quad[1], bounds[2], bounds[1], 0.5f, 1.0f);
D3Dnvg__vset(&quad[2], bounds[0], bounds[3], 0.5f, 1.0f);
D3Dnvg__vset(&quad[3], bounds[0], bounds[1], 0.5f, 1.0f);
call->uniformOffset = D3Dnvg__allocFragUniforms(D3D, 2);
if (call->uniformOffset == -1) goto error;
// Simple shader for stencil
frag = nvg__fragUniformPtr(D3D, call->uniformOffset);
memset(frag, 0, sizeof(*frag));
frag->strokeMult[1] = -1.0f;
frag->type = NSVG_SHADER_SIMPLE;
// Fill shader
D3Dnvg__convertPaint(D3D, nvg__fragUniformPtr(D3D, call->uniformOffset + D3D->fragSize), paint, scissor, fringe, fringe, -1.0f);
} else {
call->uniformOffset = D3Dnvg__allocFragUniforms(D3D, 1);
if (call->uniformOffset == -1) goto error;
// Fill shader
D3Dnvg__convertPaint(D3D, nvg__fragUniformPtr(D3D, call->uniformOffset), paint, scissor, fringe, fringe, -1.0f);
}
return;
error:
// We get here if call alloc was ok, but something else is not.
// Roll back the last call to prevent drawing it.
if (D3D->ncalls > 0) D3D->ncalls--;
}
static void D3Dnvg__renderStroke(void* uptr, struct NVGpaint* paint, NVGcompositeOperationState compositeOperation, struct NVGscissor* scissor, float fringe,
float strokeWidth, const struct NVGpath* paths, int npaths)
{
struct D3DNVGcontext* D3D = (struct D3DNVGcontext*)uptr;
struct D3DNVGcall* call = D3Dnvg__allocCall(D3D);
int i, maxverts, offset;
if (call == NULL) return;
call->type = D3DNVG_STROKE;
call->pathOffset = D3Dnvg__allocPaths(D3D, npaths);
if (call->pathOffset == -1) goto error;
call->pathCount = npaths;
call->image = paint->image;
NVG_NOTUSED(compositeOperation);
// Allocate vertices for all the paths.
maxverts = D3Dnvg__maxVertCount(paths, npaths);
offset = D3Dnvg__allocVerts(D3D, maxverts);
if (offset == -1) goto error;
for (i = 0; i < npaths; i++) {
struct D3DNVGpath* copy = &D3D->paths[call->pathOffset + i];
const struct NVGpath* path = &paths[i];
memset(copy, 0, sizeof(struct D3DNVGpath));
if (path->nstroke) {
copy->strokeOffset = offset;
copy->strokeCount = path->nstroke;
memcpy(&D3D->verts[offset], path->stroke, sizeof(struct NVGvertex) * path->nstroke);
offset += path->nstroke;
}
}
if (D3D->flags & NVG_STENCIL_STROKES) {
// Fill shader
call->uniformOffset = D3Dnvg__allocFragUniforms(D3D, 2);
if (call->uniformOffset == -1) goto error;
D3Dnvg__convertPaint(D3D, nvg__fragUniformPtr(D3D, call->uniformOffset), paint, scissor, strokeWidth, fringe, -1.0f);
D3Dnvg__convertPaint(D3D, nvg__fragUniformPtr(D3D, call->uniformOffset + D3D->fragSize), paint, scissor, strokeWidth, fringe, 1.0f - 0.5f/255.0f);
} else {
// Fill shader
call->uniformOffset = D3Dnvg__allocFragUniforms(D3D, 1);
if (call->uniformOffset == -1) goto error;
D3Dnvg__convertPaint(D3D, nvg__fragUniformPtr(D3D, call->uniformOffset), paint, scissor, strokeWidth, fringe, -1.0f);
}
return;
error:
// We get here if call alloc was ok, but something else is not.
// Roll back the last call to prevent drawing it.
if (D3D->ncalls > 0) D3D->ncalls--;
}
static void D3Dnvg__renderTriangles(void* uptr, struct NVGpaint* paint, NVGcompositeOperationState compositeOperation, struct NVGscissor* scissor,
const struct NVGvertex* verts, int nverts, float fringe)
{
struct D3DNVGcontext* D3D = (struct D3DNVGcontext*)uptr;
struct D3DNVGcall* call = D3Dnvg__allocCall(D3D);
struct D3DNVGfragUniforms* frag;
if (call == NULL) return;
call->type = D3DNVG_TRIANGLES;
call->image = paint->image;
NVG_NOTUSED(compositeOperation);
// Allocate vertices for all the paths.
call->triangleOffset = D3Dnvg__allocVerts(D3D, nverts);
if (call->triangleOffset == -1) goto error;
call->triangleCount = nverts;
memcpy(&D3D->verts[call->triangleOffset], verts, sizeof(struct NVGvertex) * nverts);
// Fill shader
call->uniformOffset = D3Dnvg__allocFragUniforms(D3D, 1);
if (call->uniformOffset == -1) goto error;
frag = nvg__fragUniformPtr(D3D, call->uniformOffset);
D3Dnvg__convertPaint(D3D, frag, paint, scissor, 1.0f, fringe, -1.0f);
frag->type = NSVG_SHADER_IMG;
return;
error:
// We get here if call alloc was ok, but something else is not.
// Roll back the last call to prevent drawing it.
if (D3D->ncalls > 0) D3D->ncalls--;
}
static void D3Dnvg__renderDelete(void* uptr)
{
struct D3DNVGcontext* D3D = (struct D3DNVGcontext*)uptr;
int i;
if (D3D == NULL)
{
return;
}
D3Dnvg__deleteShader(&D3D->shader);
for (i = 0; i < D3D->ntextures; i++)
{
if (D3D->textures[i].tex != 0 && (D3D->textures[i].flags & NVG_IMAGE_NODELETE) == 0)
{
D3D_API_RELEASE(D3D->textures[i].tex);
D3D_API_RELEASE(D3D->textures[i].resourceView);
}
}
for (i = 0; i < 4; i++)
{
D3D_API_RELEASE(D3D->pSamplerState[i]);
}
D3D_API_RELEASE(D3D->VertexBuffer.pBuffer);
D3D_API_RELEASE(D3D->pVSConstants);
D3D_API_RELEASE(D3D->pPSConstants);
D3D_API_RELEASE(D3D->pFanIndexBuffer);
D3D_API_RELEASE(D3D->pLayoutRenderTriangles);
D3D_API_RELEASE(D3D->pBSBlend);
D3D_API_RELEASE(D3D->pBSNoWrite);
D3D_API_RELEASE(D3D->pRSCull);
D3D_API_RELEASE(D3D->pRSNoCull);
D3D_API_RELEASE(D3D->pDepthStencilDrawShapes);
D3D_API_RELEASE(D3D->pDepthStencilDrawAA);
D3D_API_RELEASE(D3D->pDepthStencilFill);
D3D_API_RELEASE(D3D->pDepthStencilDefault);
// We took a reference to this
// Don't delete the device though.
D3D_API_RELEASE(D3D->pDeviceContext);
free(D3D->textures);
free(D3D->paths);
free(D3D->verts);
free(D3D->uniforms);
free(D3D->calls);
free(D3D);
}
struct NVGcontext* nvgCreateD3D11(ID3D11Device* pDevice, int flags)
{
struct NVGparams params;
struct NVGcontext* ctx = NULL;
struct D3DNVGcontext* D3D = (struct D3DNVGcontext*)malloc(sizeof(struct D3DNVGcontext));
if (D3D == NULL)
{
goto error;
}
memset(D3D, 0, sizeof(struct D3DNVGcontext));
D3D->pDevice = pDevice;
D3D_API_1(pDevice, GetImmediateContext, &D3D->pDeviceContext);
memset(&params, 0, sizeof(params));
params.renderCreate = D3Dnvg__renderCreate;
params.renderCreateTexture = D3Dnvg__renderCreateTexture;
params.renderDeleteTexture = D3Dnvg__renderDeleteTexture;
params.renderUpdateTexture = D3Dnvg__renderUpdateTexture;
params.renderGetTextureSize = D3Dnvg__renderGetTextureSize;
params.renderViewport = D3Dnvg__renderViewport;
params.renderCancel = D3Dnvg__renderCancel;
params.renderFlush = D3Dnvg__renderFlush;
params.renderFill = D3Dnvg__renderFill;
params.renderStroke = D3Dnvg__renderStroke;
params.renderTriangles = D3Dnvg__renderTriangles;
params.renderDelete = D3Dnvg__renderDelete;
params.userPtr = D3D;
params.edgeAntiAlias = flags & NVG_ANTIALIAS ? 1 : 0;
D3D->flags = flags;
ctx = nvgCreateInternal(&params);
if (ctx == NULL) goto error;
return ctx;
error:
// 'D3D' is freed by nvgDeleteInternal.
if (ctx != NULL) nvgDeleteInternal(ctx);
return NULL;
}
void nvgDeleteD3D11(struct NVGcontext* ctx)
{
nvgDeleteInternal(ctx);
}
#ifdef IMPLEMENTED_IMAGE_FUNCS
int nvd3dCreateImageFromHandle(struct NVGcontext* ctx, void* textureId, int w, int h, int flags)
{
/*struct D3DNVGcontext* gl = (struct D3DNVGcontext*)nvgInternalParams(ctx)->userPtr;
struct D3DNVGtexture* tex = D3Dnvg__allocTexture(gl);
if (tex == NULL) return 0;
tex->type = NVG_TEXTURE_RGBA;
tex->tex = textureId;
tex->flags = flags;
tex->width = w;
tex->height = h;
return tex->id;
*/
return 0;
}
unsigned int nvd3dImageHandle(struct NVGcontext* ctx, int image)
{
/*
struct D3DNVGcontext* gl = (struct D3DNVGcontext*)nvgInternalParams(ctx)->userPtr;
struct D3DNVGtexture* tex = D3Dnvg__findTexture(gl, image);
return tex->tex;*/
return 0;
}
void nvd3dImageFlags(struct NVGcontext* ctx, int image, int flags)
{
/*
struct D3DNVGcontext* gl = (struct D3DNVGcontext*)nvgInternalParams(ctx)->userPtr;
struct D3DNVGtexture* tex = D3Dnvg__findTexture(gl, image);
tex->flags = flags;
*/
}
#endif
#endif //NANOVG_D3D11_IMPLEMENTATION
#endif //NANOVG_D3D11_H