/****************************************************************************** Copyright (C) 2023 by Lain Bailey This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include // #define DISASSEMBLE_SHADERS typedef HRESULT(WINAPI *pD3DCreateBlob)(_In_ SIZE_T Size, _Out_ ID3DBlob **ppBlob); struct shader_var; struct shader_sampler; struct gs_vertex_shader; using namespace std; /* * Just to clarify, all structs, and all public. These are exporting only * via encapsulated C bindings, not C++ bindings, so the whole concept of * "public" and "private" does not matter at all for this subproject. */ static inline uint32_t GetWinVer() { struct win_version_info ver; get_win_ver(&ver); return (ver.major << 8) | ver.minor; } static inline DXGI_FORMAT ConvertGSTextureFormatResource(gs_color_format format) { switch (format) { case GS_UNKNOWN: return DXGI_FORMAT_UNKNOWN; case GS_A8: return DXGI_FORMAT_A8_UNORM; case GS_R8: return DXGI_FORMAT_R8_UNORM; case GS_RGBA: return DXGI_FORMAT_R8G8B8A8_TYPELESS; case GS_BGRX: return DXGI_FORMAT_B8G8R8X8_TYPELESS; case GS_BGRA: return DXGI_FORMAT_B8G8R8A8_TYPELESS; case GS_R10G10B10A2: return DXGI_FORMAT_R10G10B10A2_UNORM; case GS_RGBA16: return DXGI_FORMAT_R16G16B16A16_UNORM; case GS_R16: return DXGI_FORMAT_R16_UNORM; case GS_RGBA16F: return DXGI_FORMAT_R16G16B16A16_FLOAT; case GS_RGBA32F: return DXGI_FORMAT_R32G32B32A32_FLOAT; case GS_RG16F: return DXGI_FORMAT_R16G16_FLOAT; case GS_RG32F: return DXGI_FORMAT_R32G32_FLOAT; case GS_R16F: return DXGI_FORMAT_R16_FLOAT; case GS_R32F: return DXGI_FORMAT_R32_FLOAT; case GS_DXT1: return DXGI_FORMAT_BC1_UNORM; case GS_DXT3: return DXGI_FORMAT_BC2_UNORM; case GS_DXT5: return DXGI_FORMAT_BC3_UNORM; case GS_R8G8: return DXGI_FORMAT_R8G8_UNORM; case GS_RGBA_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM; case GS_BGRX_UNORM: return DXGI_FORMAT_B8G8R8X8_UNORM; case GS_BGRA_UNORM: return DXGI_FORMAT_B8G8R8A8_UNORM; case GS_RG16: return DXGI_FORMAT_R16G16_UNORM; } return DXGI_FORMAT_UNKNOWN; } static inline DXGI_FORMAT ConvertGSTextureFormatView(gs_color_format format) { switch (format) { case GS_RGBA: return DXGI_FORMAT_R8G8B8A8_UNORM; case GS_BGRX: return DXGI_FORMAT_B8G8R8X8_UNORM; case GS_BGRA: return DXGI_FORMAT_B8G8R8A8_UNORM; default: return ConvertGSTextureFormatResource(format); } } static inline DXGI_FORMAT ConvertGSTextureFormatViewLinear(gs_color_format format) { switch (format) { case GS_RGBA: return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB; case GS_BGRX: return DXGI_FORMAT_B8G8R8X8_UNORM_SRGB; case GS_BGRA: return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; default: return ConvertGSTextureFormatResource(format); } } static inline gs_color_format ConvertDXGITextureFormat(DXGI_FORMAT format) { switch (format) { case DXGI_FORMAT_A8_UNORM: return GS_A8; case DXGI_FORMAT_R8_UNORM: return GS_R8; case DXGI_FORMAT_R8G8_UNORM: return GS_R8G8; case DXGI_FORMAT_R8G8B8A8_TYPELESS: return GS_RGBA; case DXGI_FORMAT_B8G8R8X8_TYPELESS: return GS_BGRX; case DXGI_FORMAT_B8G8R8A8_TYPELESS: return GS_BGRA; case DXGI_FORMAT_R10G10B10A2_UNORM: return GS_R10G10B10A2; case DXGI_FORMAT_R16G16B16A16_UNORM: return GS_RGBA16; case DXGI_FORMAT_R16_UNORM: return GS_R16; case DXGI_FORMAT_R16G16B16A16_FLOAT: return GS_RGBA16F; case DXGI_FORMAT_R32G32B32A32_FLOAT: return GS_RGBA32F; case DXGI_FORMAT_R16G16_FLOAT: return GS_RG16F; case DXGI_FORMAT_R32G32_FLOAT: return GS_RG32F; case DXGI_FORMAT_R16_FLOAT: return GS_R16F; case DXGI_FORMAT_R32_FLOAT: return GS_R32F; case DXGI_FORMAT_BC1_UNORM: return GS_DXT1; case DXGI_FORMAT_BC2_UNORM: return GS_DXT3; case DXGI_FORMAT_BC3_UNORM: return GS_DXT5; case DXGI_FORMAT_R8G8B8A8_UNORM: return GS_RGBA_UNORM; case DXGI_FORMAT_B8G8R8X8_UNORM: return GS_BGRX_UNORM; case DXGI_FORMAT_B8G8R8A8_UNORM: return GS_BGRA_UNORM; case DXGI_FORMAT_R16G16_UNORM: return GS_RG16; } return GS_UNKNOWN; } static inline DXGI_FORMAT ConvertGSZStencilFormat(gs_zstencil_format format) { switch (format) { case GS_ZS_NONE: return DXGI_FORMAT_UNKNOWN; case GS_Z16: return DXGI_FORMAT_D16_UNORM; case GS_Z24_S8: return DXGI_FORMAT_D24_UNORM_S8_UINT; case GS_Z32F: return DXGI_FORMAT_D32_FLOAT; case GS_Z32F_S8X24: return DXGI_FORMAT_D32_FLOAT_S8X24_UINT; } return DXGI_FORMAT_UNKNOWN; } static inline D3D11_COMPARISON_FUNC ConvertGSDepthTest(gs_depth_test test) { switch (test) { case GS_NEVER: return D3D11_COMPARISON_NEVER; case GS_LESS: return D3D11_COMPARISON_LESS; case GS_LEQUAL: return D3D11_COMPARISON_LESS_EQUAL; case GS_EQUAL: return D3D11_COMPARISON_EQUAL; case GS_GEQUAL: return D3D11_COMPARISON_GREATER_EQUAL; case GS_GREATER: return D3D11_COMPARISON_GREATER; case GS_NOTEQUAL: return D3D11_COMPARISON_NOT_EQUAL; case GS_ALWAYS: return D3D11_COMPARISON_ALWAYS; } return D3D11_COMPARISON_NEVER; } static inline D3D11_STENCIL_OP ConvertGSStencilOp(gs_stencil_op_type op) { switch (op) { case GS_KEEP: return D3D11_STENCIL_OP_KEEP; case GS_ZERO: return D3D11_STENCIL_OP_ZERO; case GS_REPLACE: return D3D11_STENCIL_OP_REPLACE; case GS_INCR: return D3D11_STENCIL_OP_INCR; case GS_DECR: return D3D11_STENCIL_OP_DECR; case GS_INVERT: return D3D11_STENCIL_OP_INVERT; } return D3D11_STENCIL_OP_KEEP; } static inline D3D11_BLEND ConvertGSBlendType(gs_blend_type type) { switch (type) { case GS_BLEND_ZERO: return D3D11_BLEND_ZERO; case GS_BLEND_ONE: return D3D11_BLEND_ONE; case GS_BLEND_SRCCOLOR: return D3D11_BLEND_SRC_COLOR; case GS_BLEND_INVSRCCOLOR: return D3D11_BLEND_INV_SRC_COLOR; case GS_BLEND_SRCALPHA: return D3D11_BLEND_SRC_ALPHA; case GS_BLEND_INVSRCALPHA: return D3D11_BLEND_INV_SRC_ALPHA; case GS_BLEND_DSTCOLOR: return D3D11_BLEND_DEST_COLOR; case GS_BLEND_INVDSTCOLOR: return D3D11_BLEND_INV_DEST_COLOR; case GS_BLEND_DSTALPHA: return D3D11_BLEND_DEST_ALPHA; case GS_BLEND_INVDSTALPHA: return D3D11_BLEND_INV_DEST_ALPHA; case GS_BLEND_SRCALPHASAT: return D3D11_BLEND_SRC_ALPHA_SAT; } return D3D11_BLEND_ONE; } static inline D3D11_BLEND_OP ConvertGSBlendOpType(gs_blend_op_type type) { switch (type) { case GS_BLEND_OP_ADD: return D3D11_BLEND_OP_ADD; case GS_BLEND_OP_SUBTRACT: return D3D11_BLEND_OP_SUBTRACT; case GS_BLEND_OP_REVERSE_SUBTRACT: return D3D11_BLEND_OP_REV_SUBTRACT; case GS_BLEND_OP_MIN: return D3D11_BLEND_OP_MIN; case GS_BLEND_OP_MAX: return D3D11_BLEND_OP_MAX; } return D3D11_BLEND_OP_ADD; } static inline D3D11_CULL_MODE ConvertGSCullMode(gs_cull_mode mode) { switch (mode) { case GS_BACK: return D3D11_CULL_BACK; case GS_FRONT: return D3D11_CULL_FRONT; case GS_NEITHER: return D3D11_CULL_NONE; } return D3D11_CULL_BACK; } static inline D3D11_PRIMITIVE_TOPOLOGY ConvertGSTopology(gs_draw_mode mode) { switch (mode) { case GS_POINTS: return D3D11_PRIMITIVE_TOPOLOGY_POINTLIST; case GS_LINES: return D3D11_PRIMITIVE_TOPOLOGY_LINELIST; case GS_LINESTRIP: return D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP; case GS_TRIS: return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST; case GS_TRISTRIP: return D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; } return D3D11_PRIMITIVE_TOPOLOGY_POINTLIST; } /* exception-safe RAII wrapper for vertex buffer data (NOTE: not copy-safe) */ struct VBDataPtr { gs_vb_data *data; inline VBDataPtr(gs_vb_data *data) : data(data) {} inline ~VBDataPtr() { gs_vbdata_destroy(data); } }; enum class gs_type { gs_vertex_buffer, gs_index_buffer, gs_texture_2d, gs_zstencil_buffer, gs_stage_surface, gs_sampler_state, gs_vertex_shader, gs_pixel_shader, gs_duplicator, gs_swap_chain, gs_timer, gs_timer_range, gs_texture_3d, }; struct gs_obj { gs_device_t *device; gs_type obj_type; gs_obj *next; gs_obj **prev_next; inline gs_obj() : device(nullptr), next(nullptr), prev_next(nullptr) {} gs_obj(gs_device_t *device, gs_type type); virtual ~gs_obj(); }; struct gs_vertex_buffer : gs_obj { ComPtr vertexBuffer; ComPtr normalBuffer; ComPtr colorBuffer; ComPtr tangentBuffer; vector> uvBuffers; bool dynamic; VBDataPtr vbd; size_t numVerts; vector uvSizes; void FlushBuffer(ID3D11Buffer *buffer, void *array, size_t elementSize); UINT MakeBufferList(gs_vertex_shader *shader, ID3D11Buffer **buffers, uint32_t *strides); void InitBuffer(const size_t elementSize, const size_t numVerts, void *array, ID3D11Buffer **buffer); void BuildBuffers(); inline void Release() { vertexBuffer.Release(); normalBuffer.Release(); colorBuffer.Release(); tangentBuffer.Release(); uvBuffers.clear(); } void Rebuild(); gs_vertex_buffer(gs_device_t *device, struct gs_vb_data *data, uint32_t flags); }; /* exception-safe RAII wrapper for index buffer data (NOTE: not copy-safe) */ struct DataPtr { void *data; inline DataPtr(void *data) : data(data) {} inline ~DataPtr() { bfree(data); } }; struct gs_index_buffer : gs_obj { ComPtr indexBuffer; bool dynamic; gs_index_type type; size_t indexSize; size_t num; DataPtr indices; D3D11_BUFFER_DESC bd = {}; D3D11_SUBRESOURCE_DATA srd = {}; void InitBuffer(); void Rebuild(ID3D11Device *dev); inline void Release() { indexBuffer.Release(); } gs_index_buffer(gs_device_t *device, enum gs_index_type type, void *indices, size_t num, uint32_t flags); }; struct gs_timer : gs_obj { ComPtr query_begin; ComPtr query_end; void Rebuild(ID3D11Device *dev); inline void Release() { query_begin.Release(); query_end.Release(); } gs_timer(gs_device_t *device); }; struct gs_timer_range : gs_obj { ComPtr query_disjoint; void Rebuild(ID3D11Device *dev); inline void Release() { query_disjoint.Release(); } gs_timer_range(gs_device_t *device); }; struct gs_texture : gs_obj { gs_texture_type type; uint32_t levels; gs_color_format format; ComPtr shaderRes; ComPtr shaderResLinear; D3D11_SHADER_RESOURCE_VIEW_DESC viewDesc{}; D3D11_SHADER_RESOURCE_VIEW_DESC viewDescLinear{}; void Rebuild(ID3D11Device *dev); inline gs_texture(gs_texture_type type, uint32_t levels, gs_color_format format) : type(type), levels(levels), format(format) { } inline gs_texture(gs_device *device, gs_type obj_type, gs_texture_type type) : gs_obj(device, obj_type), type(type) { } inline gs_texture(gs_device *device, gs_type obj_type, gs_texture_type type, uint32_t levels, gs_color_format format) : gs_obj(device, obj_type), type(type), levels(levels), format(format) { } }; struct gs_texture_2d : gs_texture { ComPtr texture; ComPtr renderTarget[6]; ComPtr renderTargetLinear[6]; ComPtr gdiSurface; uint32_t width = 0, height = 0; uint32_t flags = 0; DXGI_FORMAT dxgiFormatResource = DXGI_FORMAT_UNKNOWN; DXGI_FORMAT dxgiFormatView = DXGI_FORMAT_UNKNOWN; DXGI_FORMAT dxgiFormatViewLinear = DXGI_FORMAT_UNKNOWN; bool isRenderTarget = false; bool isGDICompatible = false; bool isDynamic = false; bool isShared = false; bool genMipmaps = false; uint32_t sharedHandle = GS_INVALID_HANDLE; gs_texture_2d *pairedTexture = nullptr; bool twoPlane = false; bool chroma = false; bool acquired = false; vector> data; vector srd; D3D11_TEXTURE2D_DESC td = {}; void InitSRD(vector &srd); void InitTexture(const uint8_t *const *data); void InitResourceView(); void InitRenderTargets(); void BackupTexture(const uint8_t *const *data); void GetSharedHandle(IDXGIResource *dxgi_res); void RebuildSharedTextureFallback(); void Rebuild(ID3D11Device *dev); void RebuildPaired_Y(ID3D11Device *dev); void RebuildPaired_UV(ID3D11Device *dev); inline void Release() { texture.Release(); for (ComPtr &rt : renderTarget) rt.Release(); for (ComPtr &rt : renderTargetLinear) rt.Release(); gdiSurface.Release(); shaderRes.Release(); shaderResLinear.Release(); } inline gs_texture_2d() : gs_texture(GS_TEXTURE_2D, 0, GS_UNKNOWN) {} gs_texture_2d(gs_device_t *device, uint32_t width, uint32_t height, gs_color_format colorFormat, uint32_t levels, const uint8_t *const *data, uint32_t flags, gs_texture_type type, bool gdiCompatible, bool twoPlane = false); gs_texture_2d(gs_device_t *device, ID3D11Texture2D *nv12, uint32_t flags); gs_texture_2d(gs_device_t *device, uint32_t handle, bool ntHandle = false); gs_texture_2d(gs_device_t *device, ID3D11Texture2D *obj); }; struct gs_texture_3d : gs_texture { ComPtr texture; uint32_t width = 0, height = 0, depth = 0; uint32_t flags = 0; DXGI_FORMAT dxgiFormatResource = DXGI_FORMAT_UNKNOWN; DXGI_FORMAT dxgiFormatView = DXGI_FORMAT_UNKNOWN; DXGI_FORMAT dxgiFormatViewLinear = DXGI_FORMAT_UNKNOWN; bool isDynamic = false; bool isShared = false; bool genMipmaps = false; uint32_t sharedHandle = GS_INVALID_HANDLE; bool chroma = false; bool acquired = false; vector> data; vector srd; D3D11_TEXTURE3D_DESC td = {}; void InitSRD(vector &srd); void InitTexture(const uint8_t *const *data); void InitResourceView(); void BackupTexture(const uint8_t *const *data); void GetSharedHandle(IDXGIResource *dxgi_res); void RebuildSharedTextureFallback(); void Rebuild(ID3D11Device *dev); void RebuildNV12_Y(ID3D11Device *dev); void RebuildNV12_UV(ID3D11Device *dev); inline void Release() { texture.Release(); shaderRes.Release(); } inline gs_texture_3d() : gs_texture(GS_TEXTURE_3D, 0, GS_UNKNOWN) {} gs_texture_3d(gs_device_t *device, uint32_t width, uint32_t height, uint32_t depth, gs_color_format colorFormat, uint32_t levels, const uint8_t *const *data, uint32_t flags); gs_texture_3d(gs_device_t *device, uint32_t handle); }; struct gs_zstencil_buffer : gs_obj { ComPtr texture; ComPtr view; uint32_t width, height; gs_zstencil_format format; DXGI_FORMAT dxgiFormat; D3D11_TEXTURE2D_DESC td = {}; D3D11_DEPTH_STENCIL_VIEW_DESC dsvd = {}; void InitBuffer(); void Rebuild(ID3D11Device *dev); inline void Release() { texture.Release(); view.Release(); } inline gs_zstencil_buffer() : width(0), height(0), dxgiFormat(DXGI_FORMAT_UNKNOWN) { } gs_zstencil_buffer(gs_device_t *device, uint32_t width, uint32_t height, gs_zstencil_format format); }; struct gs_stage_surface : gs_obj { ComPtr texture; D3D11_TEXTURE2D_DESC td = {}; uint32_t width, height; gs_color_format format; DXGI_FORMAT dxgiFormat; void Rebuild(ID3D11Device *dev); inline void Release() { texture.Release(); } gs_stage_surface(gs_device_t *device, uint32_t width, uint32_t height, gs_color_format colorFormat); gs_stage_surface(gs_device_t *device, uint32_t width, uint32_t height, bool p010); }; struct gs_sampler_state : gs_obj { ComPtr state; D3D11_SAMPLER_DESC sd = {}; gs_sampler_info info; void Rebuild(ID3D11Device *dev); inline void Release() { state.Release(); } gs_sampler_state(gs_device_t *device, const gs_sampler_info *info); }; struct gs_shader_param { string name; gs_shader_param_type type; uint32_t textureID; struct gs_sampler_state *nextSampler = nullptr; int arrayCount; size_t pos; vector curValue; vector defaultValue; bool changed; gs_shader_param(shader_var &var, uint32_t &texCounter); }; struct ShaderError { ComPtr errors; HRESULT hr; inline ShaderError(const ComPtr &errors, HRESULT hr) : errors(errors), hr(hr) { } }; struct gs_shader : gs_obj { gs_shader_type type; vector params; ComPtr constants; size_t constantSize; D3D11_BUFFER_DESC bd = {}; vector data; inline void UpdateParam(vector &constData, gs_shader_param ¶m, bool &upload); void UploadParams(); void BuildConstantBuffer(); void Compile(const char *shaderStr, const char *file, const char *target, ID3D10Blob **shader); inline gs_shader(gs_device_t *device, gs_type obj_type, gs_shader_type type) : gs_obj(device, obj_type), type(type), constantSize(0) { } virtual ~gs_shader() {} }; struct ShaderSampler { string name; gs_sampler_state sampler; inline ShaderSampler(const char *name, gs_device_t *device, gs_sampler_info *info) : name(name), sampler(device, info) { } }; struct gs_vertex_shader : gs_shader { ComPtr shader; ComPtr layout; gs_shader_param *world, *viewProj; vector layoutData; bool hasNormals; bool hasColors; bool hasTangents; uint32_t nTexUnits; void Rebuild(ID3D11Device *dev); inline void Release() { shader.Release(); layout.Release(); constants.Release(); } inline uint32_t NumBuffersExpected() const { uint32_t count = nTexUnits + 1; if (hasNormals) count++; if (hasColors) count++; if (hasTangents) count++; return count; } void GetBuffersExpected(const vector &inputs); gs_vertex_shader(gs_device_t *device, const char *file, const char *shaderString); }; struct gs_duplicator : gs_obj { ComPtr duplicator; gs_texture_2d *texture; bool hdr = false; enum gs_color_space color_space = GS_CS_SRGB; float sdr_white_nits = 80.f; int idx; long refs; bool updated; void Start(); inline void Release() { duplicator.Release(); } gs_duplicator(gs_device_t *device, int monitor_idx); ~gs_duplicator(); }; struct gs_pixel_shader : gs_shader { ComPtr shader; vector> samplers; void Rebuild(ID3D11Device *dev); inline void Release() { shader.Release(); constants.Release(); } inline void GetSamplerStates(ID3D11SamplerState **states) { size_t i; for (i = 0; i < samplers.size(); i++) states[i] = samplers[i]->sampler.state; for (; i < GS_MAX_TEXTURES; i++) states[i] = NULL; } gs_pixel_shader(gs_device_t *device, const char *file, const char *shaderString); }; struct gs_swap_chain : gs_obj { HWND hwnd; gs_init_data initData; DXGI_SWAP_CHAIN_DESC swapDesc = {}; gs_color_space space; gs_texture_2d target; gs_zstencil_buffer zs; ComPtr swap; HANDLE hWaitable = NULL; void InitTarget(uint32_t cx, uint32_t cy); void InitZStencilBuffer(uint32_t cx, uint32_t cy); void Resize(uint32_t cx, uint32_t cy, gs_color_format format); void Init(); void Rebuild(ID3D11Device *dev); inline void Release() { target.Release(); zs.Release(); if (hWaitable) { CloseHandle(hWaitable); hWaitable = NULL; } swap.Clear(); } gs_swap_chain(gs_device *device, const gs_init_data *data); virtual ~gs_swap_chain(); }; struct BlendState { bool blendEnabled; gs_blend_type srcFactorC; gs_blend_type destFactorC; gs_blend_type srcFactorA; gs_blend_type destFactorA; gs_blend_op_type op; bool redEnabled; bool greenEnabled; bool blueEnabled; bool alphaEnabled; inline BlendState() : blendEnabled(true), srcFactorC(GS_BLEND_SRCALPHA), destFactorC(GS_BLEND_INVSRCALPHA), srcFactorA(GS_BLEND_ONE), destFactorA(GS_BLEND_INVSRCALPHA), op(GS_BLEND_OP_ADD), redEnabled(true), greenEnabled(true), blueEnabled(true), alphaEnabled(true) { } inline BlendState(const BlendState &state) { memcpy(this, &state, sizeof(BlendState)); } }; struct SavedBlendState : BlendState { ComPtr state; D3D11_BLEND_DESC bd; void Rebuild(ID3D11Device *dev); inline void Release() { state.Release(); } inline SavedBlendState(const BlendState &val, D3D11_BLEND_DESC &desc) : BlendState(val), bd(desc) { } }; struct StencilSide { gs_depth_test test; gs_stencil_op_type fail; gs_stencil_op_type zfail; gs_stencil_op_type zpass; inline StencilSide() : test(GS_ALWAYS), fail(GS_KEEP), zfail(GS_KEEP), zpass(GS_KEEP) { } }; struct ZStencilState { bool depthEnabled; bool depthWriteEnabled; gs_depth_test depthFunc; bool stencilEnabled; bool stencilWriteEnabled; StencilSide stencilFront; StencilSide stencilBack; inline ZStencilState() : depthEnabled(true), depthWriteEnabled(true), depthFunc(GS_LESS), stencilEnabled(false), stencilWriteEnabled(true) { } inline ZStencilState(const ZStencilState &state) { memcpy(this, &state, sizeof(ZStencilState)); } }; struct SavedZStencilState : ZStencilState { ComPtr state; D3D11_DEPTH_STENCIL_DESC dsd; void Rebuild(ID3D11Device *dev); inline void Release() { state.Release(); } inline SavedZStencilState(const ZStencilState &val, D3D11_DEPTH_STENCIL_DESC desc) : ZStencilState(val), dsd(desc) { } }; struct RasterState { gs_cull_mode cullMode; bool scissorEnabled; inline RasterState() : cullMode(GS_BACK), scissorEnabled(false) {} inline RasterState(const RasterState &state) { memcpy(this, &state, sizeof(RasterState)); } }; struct SavedRasterState : RasterState { ComPtr state; D3D11_RASTERIZER_DESC rd; void Rebuild(ID3D11Device *dev); inline void Release() { state.Release(); } inline SavedRasterState(const RasterState &val, D3D11_RASTERIZER_DESC &desc) : RasterState(val), rd(desc) { } }; struct mat4float { float mat[16]; }; struct gs_monitor_color_info { bool hdr; UINT bits_per_color; ULONG sdr_white_nits; gs_monitor_color_info(bool hdr, int bits_per_color, ULONG sdr_white_nits) : hdr(hdr), bits_per_color(bits_per_color), sdr_white_nits(sdr_white_nits) { } }; struct gs_device { ComPtr factory; ComPtr adapter; ComPtr device; ComPtr context; uint32_t adpIdx = 0; bool nv12Supported = false; bool p010Supported = false; bool fastClearSupported = false; gs_texture_2d *curRenderTarget = nullptr; gs_zstencil_buffer *curZStencilBuffer = nullptr; int curRenderSide = 0; enum gs_color_space curColorSpace = GS_CS_SRGB; bool curFramebufferSrgb = false; bool curFramebufferInvalidate = false; gs_texture *curTextures[GS_MAX_TEXTURES]; gs_sampler_state *curSamplers[GS_MAX_TEXTURES]; gs_vertex_buffer *curVertexBuffer = nullptr; gs_index_buffer *curIndexBuffer = nullptr; gs_vertex_shader *curVertexShader = nullptr; gs_pixel_shader *curPixelShader = nullptr; gs_swap_chain *curSwapChain = nullptr; gs_vertex_buffer *lastVertexBuffer = nullptr; gs_vertex_shader *lastVertexShader = nullptr; bool zstencilStateChanged = true; bool rasterStateChanged = true; bool blendStateChanged = true; ZStencilState zstencilState; RasterState rasterState; BlendState blendState; vector zstencilStates; vector rasterStates; vector blendStates; ID3D11DepthStencilState *curDepthStencilState = nullptr; ID3D11RasterizerState *curRasterState = nullptr; ID3D11BlendState *curBlendState = nullptr; D3D11_PRIMITIVE_TOPOLOGY curToplogy; gs_rect viewport; vector projStack; matrix4 curProjMatrix; matrix4 curViewMatrix; matrix4 curViewProjMatrix; vector loss_callbacks; gs_obj *first_obj = nullptr; vector> monitor_to_hdr; void InitFactory(); void InitAdapter(uint32_t adapterIdx); void InitDevice(uint32_t adapterIdx); ID3D11DepthStencilState *AddZStencilState(); ID3D11RasterizerState *AddRasterState(); ID3D11BlendState *AddBlendState(); void UpdateZStencilState(); void UpdateRasterState(); void UpdateBlendState(); void LoadVertexBufferData(); void CopyTex(ID3D11Texture2D *dst, uint32_t dst_x, uint32_t dst_y, gs_texture_t *src, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h); void UpdateViewProjMatrix(); void FlushOutputViews(); void RebuildDevice(); bool HasBadNV12Output(); gs_monitor_color_info GetMonitorColorInfo(HMONITOR hMonitor); gs_device(uint32_t adapterIdx); ~gs_device(); }; extern "C" EXPORT int device_texture_acquire_sync(gs_texture_t *tex, uint64_t key, uint32_t ms);