/****************************************************************************** Copyright (C) 2013 by Hugh 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 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() { OSVERSIONINFO ovi; ovi.dwOSVersionInfoSize = sizeof(ovi); GetVersionEx(&ovi); return (ovi.dwMajorVersion << 8) | (ovi.dwMinorVersion); } static inline DXGI_FORMAT ConvertGSTextureFormat(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_UNORM; case GS_BGRX: return DXGI_FORMAT_B8G8R8X8_UNORM; case GS_BGRA: return DXGI_FORMAT_B8G8R8A8_UNORM; 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; } return DXGI_FORMAT_UNKNOWN; } static inline gs_color_format ConvertDXGITextureFormat(DXGI_FORMAT format) { switch ((unsigned long)format) { case DXGI_FORMAT_A8_UNORM: return GS_A8; case DXGI_FORMAT_R8_UNORM: return GS_R8; case DXGI_FORMAT_R8G8B8A8_UNORM: return GS_RGBA; case DXGI_FORMAT_B8G8R8X8_UNORM: return GS_BGRX; case DXGI_FORMAT_B8G8R8A8_UNORM: 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; } 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_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 void Clear() {gs_vbdata_destroy(data); data = nullptr;} inline VBDataPtr(gs_vb_data *data) : data(data) {} inline ~VBDataPtr() {gs_vbdata_destroy(data);} }; struct gs_vertex_buffer { ComPtr vertexBuffer; ComPtr normalBuffer; ComPtr colorBuffer; ComPtr tangentBuffer; vector> uvBuffers; gs_device_t *device; bool dynamic; VBDataPtr vbd; size_t numVerts; vector uvSizes; void FlushBuffer(ID3D11Buffer *buffer, void *array, size_t elementSize); void MakeBufferList(gs_vertex_shader *shader, vector &buffers, vector &strides); inline void InitBuffer(const size_t elementSize, const size_t numVerts, void *array, ID3D11Buffer **buffer); 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 { ComPtr indexBuffer; gs_device_t *device; bool dynamic; gs_index_type type; size_t indexSize; size_t num; DataPtr indices; void InitBuffer(); gs_index_buffer(gs_device_t *device, enum gs_index_type type, void *indices, size_t num, uint32_t flags); }; struct gs_texture { gs_texture_type type; gs_device *device; uint32_t levels; gs_color_format format; ComPtr shaderRes; inline gs_texture() {} inline gs_texture(gs_device *device, gs_texture_type type, uint32_t levels, gs_color_format format) : type (type), device (device), levels (levels), format (format) { } virtual ~gs_texture() {} }; struct gs_texture_2d : gs_texture { ComPtr texture; ComPtr renderTarget[6]; ComPtr gdiSurface; uint32_t width = 0, height = 0; DXGI_FORMAT dxgiFormat = DXGI_FORMAT_UNKNOWN; bool isRenderTarget = false; bool isGDICompatible = false; bool isDynamic = false; bool isShared = false; bool genMipmaps = false; uint32_t sharedHandle = 0; void InitSRD(vector &srd, const uint8_t **data); void InitTexture(const uint8_t **data); void InitResourceView(); void InitRenderTargets(); inline gs_texture_2d() : gs_texture (NULL, 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 **data, uint32_t flags, gs_texture_type type, bool gdiCompatible, bool shared); gs_texture_2d(gs_device_t *device, uint32_t handle); }; struct gs_zstencil_buffer { ComPtr texture; ComPtr view; gs_device *device; uint32_t width, height; gs_zstencil_format format; DXGI_FORMAT dxgiFormat; void InitBuffer(); inline gs_zstencil_buffer() : device (NULL), 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 { ComPtr texture; gs_device *device; uint32_t width, height; gs_color_format format; DXGI_FORMAT dxgiFormat; gs_stage_surface(gs_device_t *device, uint32_t width, uint32_t height, gs_color_format colorFormat); }; struct gs_sampler_state { ComPtr state; gs_device_t *device; gs_sampler_info info; 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; 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_device_t *device; gs_shader_type type; vector params; ComPtr constants; size_t constantSize; 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_shader_type type) : device (device), 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; bool hasNormals; bool hasColors; bool hasTangents; uint32_t nTexUnits; 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 { ComPtr duplicator; gs_texture_2d *texture; gs_device_t *device; gs_duplicator(gs_device_t *device, int monitor_idx); ~gs_duplicator(); }; struct gs_pixel_shader : gs_shader { ComPtr shader; vector samplers; 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_device *device; uint32_t numBuffers; HWND hwnd; gs_texture_2d target; gs_zstencil_buffer zs; ComPtr swap; void InitTarget(uint32_t cx, uint32_t cy); void InitZStencilBuffer(uint32_t cx, uint32_t cy); void Resize(uint32_t cx, uint32_t cy); void Init(const gs_init_data *data); inline gs_swap_chain() : device (NULL), numBuffers (0), hwnd (NULL) { } gs_swap_chain(gs_device *device, const gs_init_data *data); }; struct BlendState { bool blendEnabled; gs_blend_type srcFactor; gs_blend_type destFactor; bool redEnabled; bool greenEnabled; bool blueEnabled; bool alphaEnabled; inline BlendState() : blendEnabled (true), srcFactor (GS_BLEND_SRCALPHA), destFactor (GS_BLEND_INVSRCALPHA), redEnabled (true), greenEnabled (true), blueEnabled (true), alphaEnabled (true) { } inline BlendState(const BlendState &state) { memcpy(this, &state, sizeof(BlendState)); } }; struct SavedBlendState : BlendState { ComPtr state; inline SavedBlendState(const BlendState &val) : BlendState(val) { } }; 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; inline SavedZStencilState(const ZStencilState &val) : ZStencilState (val) { } }; 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; inline SavedRasterState(const RasterState &val) : RasterState (val) { } }; struct mat4float { float mat[16]; }; struct gs_device { ComPtr factory; ComPtr device; ComPtr context; gs_swap_chain defaultSwap; gs_texture_2d *curRenderTarget = nullptr; gs_zstencil_buffer *curZStencilBuffer = nullptr; int curRenderSide = 0; 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; 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; pD3DCompile d3dCompile = nullptr; gs_rect viewport; vector projStack; matrix4 curProjMatrix; matrix4 curViewMatrix; matrix4 curViewProjMatrix; void InitCompiler(); void InitFactory(uint32_t adapterIdx, IDXGIAdapter1 **adapter); void InitDevice(const gs_init_data *data, IDXGIAdapter *adapter); ID3D11DepthStencilState *AddZStencilState(); ID3D11RasterizerState *AddRasterState(); ID3D11BlendState *AddBlendState(); void UpdateZStencilState(); void UpdateRasterState(); void UpdateBlendState(); inline 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(); gs_device(const gs_init_data *data); };