CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Common/GPU/D3D11/thin3d_d3d11.cpp
Views: 1401
#include "ppsspp_config.h"12#include "Common/GPU/thin3d.h"3#if PPSSPP_PLATFORM(UWP)4#define ptr_D3DCompile D3DCompile5#else6#include "Common/GPU/D3D11/D3D11Loader.h"7#endif8#include "Common/System/Display.h"910#include "Common/Data/Convert/ColorConv.h"11#include "Common/Data/Convert/SmallDataConvert.h"12#include "Common/Data/Encoding/Utf8.h"13#include "Common/TimeUtil.h"14#include "Common/Log.h"1516#include <map>1718#include <cfloat>19#include <D3Dcommon.h>20#include <d3d11.h>21#include <d3d11_1.h>22#include <D3Dcompiler.h>2324#ifdef __MINGW32__25#undef __uuidof26#define __uuidof(type) IID_##type27#endif2829namespace Draw {3031static constexpr int MAX_BOUND_TEXTURES = 8;3233// A problem is that we can't get the D3Dcompiler.dll without using a later SDK than 7.1, which was the last that34// supported XP. A possible solution might be here:35// https://tedwvc.wordpress.com/2014/01/01/how-to-target-xp-with-vc2012-or-vc2013-and-continue-to-use-the-windows-8-x-sdk/3637class D3D11Pipeline;38class D3D11BlendState;39class D3D11DepthStencilState;40class D3D11SamplerState;41class D3D11Buffer;42class D3D11RasterState;43class D3D11Framebuffer;4445// This must stay POD for the memcmp to work reliably.46struct D3D11DepthStencilKey {47DepthStencilStateDesc desc;48u8 writeMask;49u8 compareMask;5051bool operator < (const D3D11DepthStencilKey &other) const {52return memcmp(this, &other, sizeof(D3D11DepthStencilKey)) < 0;53}54};555657class D3D11DepthStencilState : public DepthStencilState {58public:59~D3D11DepthStencilState() {}60DepthStencilStateDesc desc;61};6263class D3D11DrawContext : public DrawContext {64public:65D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *deviceContext, ID3D11Device1 *device1, ID3D11DeviceContext1 *deviceContext1, IDXGISwapChain *swapChain, D3D_FEATURE_LEVEL featureLevel, HWND hWnd, std::vector<std::string> deviceList, int maxInflightFrames);66~D3D11DrawContext();6768const DeviceCaps &GetDeviceCaps() const override {69return caps_;70}71std::vector<std::string> GetDeviceList() const override {72return deviceList_;73}74uint32_t GetSupportedShaderLanguages() const override {75return (uint32_t)ShaderLanguage::HLSL_D3D11;76}77uint32_t GetDataFormatSupport(DataFormat fmt) const override;7879InputLayout *CreateInputLayout(const InputLayoutDesc &desc) override;80DepthStencilState *CreateDepthStencilState(const DepthStencilStateDesc &desc) override;81BlendState *CreateBlendState(const BlendStateDesc &desc) override;82SamplerState *CreateSamplerState(const SamplerStateDesc &desc) override;83RasterState *CreateRasterState(const RasterStateDesc &desc) override;84Buffer *CreateBuffer(size_t size, uint32_t usageFlags) override;85Pipeline *CreateGraphicsPipeline(const PipelineDesc &desc, const char *tag) override;86Texture *CreateTexture(const TextureDesc &desc) override;87ShaderModule *CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t dataSize, const char *tag) override;88Framebuffer *CreateFramebuffer(const FramebufferDesc &desc) override;8990void UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) override;91void UpdateTextureLevels(Texture *texture, const uint8_t **data, TextureCallback initDataCallback, int numLevels) override;9293void CopyFramebufferImage(Framebuffer *src, int level, int x, int y, int z, Framebuffer *dst, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBits, const char *tag) override;94bool BlitFramebuffer(Framebuffer *src, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dst, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter, const char *tag) override;95bool CopyFramebufferToMemory(Framebuffer *src, int channelBits, int x, int y, int w, int h, Draw::DataFormat format, void *pixels, int pixelStride, ReadbackMode mode, const char *tag) override;9697// These functions should be self explanatory.98void BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) override;99void BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) override;100101void GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) override;102103void Invalidate(InvalidationFlags flags) override;104105void BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) override;106void BindNativeTexture(int index, void *nativeTexture) override;107void BindSamplerStates(int start, int count, SamplerState **states) override;108void BindVertexBuffer(Buffer *buffers, int offset) override;109void BindIndexBuffer(Buffer *indexBuffer, int offset) override;110void BindPipeline(Pipeline *pipeline) override;111112void UpdateDynamicUniformBuffer(const void *ub, size_t size) override;113114// Raster state115void SetScissorRect(int left, int top, int width, int height) override;116void SetViewport(const Viewport &viewport) override;117void SetBlendFactor(float color[4]) override {118if (memcmp(blendFactor_, color, sizeof(float) * 4)) {119memcpy(blendFactor_, color, sizeof(float) * 4);120blendFactorDirty_ = true;121}122}123void SetStencilParams(uint8_t refValue, uint8_t writeMask, uint8_t compareMask) override {124stencilRef_ = refValue;125stencilWriteMask_ = writeMask;126stencilCompareMask_ = compareMask;127stencilDirty_ = true;128}129130131void Draw(int vertexCount, int offset) override;132void DrawIndexed(int vertexCount, int offset) override;133void DrawUP(const void *vdata, int vertexCount) override;134void Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) override;135136void BeginFrame(DebugFlags debugFlags) override;137void EndFrame() override;138void Present(PresentMode presentMode, int vblanks) override;139140int GetFrameCount() override { return frameCount_; }141142std::string GetInfoString(InfoField info) const override {143switch (info) {144case InfoField::APIVERSION: return "Direct3D 11";145case InfoField::VENDORSTRING: return adapterDesc_;146case InfoField::VENDOR: return "";147case InfoField::DRIVER: return "-";148case InfoField::SHADELANGVERSION:149switch (featureLevel_) {150case D3D_FEATURE_LEVEL_9_1: return "Feature Level 9.1"; break;151case D3D_FEATURE_LEVEL_9_2: return "Feature Level 9.2"; break;152case D3D_FEATURE_LEVEL_9_3: return "Feature Level 9.3"; break;153case D3D_FEATURE_LEVEL_10_0: return "Feature Level 10.0"; break;154case D3D_FEATURE_LEVEL_10_1: return "Feature Level 10.1"; break;155case D3D_FEATURE_LEVEL_11_0: return "Feature Level 11.0"; break;156case D3D_FEATURE_LEVEL_11_1: return "Feature Level 11.1"; break;157case D3D_FEATURE_LEVEL_12_0: return "Feature Level 12.0"; break;158case D3D_FEATURE_LEVEL_12_1: return "Feature Level 12.1"; break;159}160return "Unknown feature level";161case InfoField::APINAME: return "Direct3D 11";162default: return "?";163}164}165166uint64_t GetNativeObject(NativeObject obj, void *srcObject) override;167168void HandleEvent(Event ev, int width, int height, void *param1, void *param2) override;169170void SetInvalidationCallback(InvalidationCallback callback) override {171invalidationCallback_ = callback;172}173174private:175void ApplyCurrentState();176177ID3D11DepthStencilState *GetCachedDepthStencilState(const D3D11DepthStencilState *state, uint8_t stencilWriteMask, uint8_t stencilCompareMask);178179HWND hWnd_;180ID3D11Device *device_;181ID3D11Device1 *device1_;182ID3D11DeviceContext *context_;183ID3D11DeviceContext1 *context1_;184IDXGISwapChain *swapChain_;185186ID3D11Texture2D *bbRenderTargetTex_ = nullptr; // NOT OWNED187ID3D11RenderTargetView *bbRenderTargetView_ = nullptr;188// Strictly speaking we don't need a depth buffer for the backbuffer.189ID3D11Texture2D *bbDepthStencilTex_ = nullptr;190ID3D11DepthStencilView *bbDepthStencilView_ = nullptr;191192AutoRef<Framebuffer> curRenderTarget_;193ID3D11RenderTargetView *curRenderTargetView_ = nullptr;194ID3D11DepthStencilView *curDepthStencilView_ = nullptr;195// Needed to rotate stencil/viewport rectangles properly196int bbWidth_ = 0;197int bbHeight_ = 0;198int curRTWidth_ = 0;199int curRTHeight_ = 0;200201AutoRef<D3D11Pipeline> curPipeline_;202DeviceCaps caps_{};203204AutoRef<D3D11BlendState> curBlend_;205AutoRef<D3D11DepthStencilState> curDepthStencil_;206AutoRef<D3D11RasterState> curRaster_;207208std::map<D3D11DepthStencilKey, ID3D11DepthStencilState *> depthStencilCache_;209210ID3D11InputLayout *curInputLayout_ = nullptr;211ID3D11VertexShader *curVS_ = nullptr;212ID3D11PixelShader *curPS_ = nullptr;213ID3D11GeometryShader *curGS_ = nullptr;214D3D11_PRIMITIVE_TOPOLOGY curTopology_ = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED;215216ID3D11Buffer *nextVertexBuffer_ = nullptr;217UINT nextVertexBufferOffset_ = 0;218219bool dirtyIndexBuffer_ = false;220ID3D11Buffer *nextIndexBuffer_ = nullptr;221UINT nextIndexBufferOffset_ = 0;222223InvalidationCallback invalidationCallback_;224int frameCount_ = FRAME_TIME_HISTORY_LENGTH;225226// Dynamic state227float blendFactor_[4]{};228bool blendFactorDirty_ = false;229uint8_t stencilRef_ = 0;230uint8_t stencilWriteMask_ = 0xFF;231uint8_t stencilCompareMask_ = 0xFF;232233bool stencilDirty_ = true;234235// Temporaries236ID3D11Texture2D *packTexture_ = nullptr;237Buffer *upBuffer_ = nullptr;238239// System info240D3D_FEATURE_LEVEL featureLevel_;241std::string adapterDesc_;242std::vector<std::string> deviceList_;243};244245D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *deviceContext, ID3D11Device1 *device1, ID3D11DeviceContext1 *deviceContext1, IDXGISwapChain *swapChain, D3D_FEATURE_LEVEL featureLevel, HWND hWnd, std::vector<std::string> deviceList, int maxInflightFrames)246: hWnd_(hWnd),247device_(device),248context_(deviceContext1),249device1_(device1),250context1_(deviceContext1),251featureLevel_(featureLevel),252swapChain_(swapChain),253deviceList_(deviceList) {254255// We no longer support Windows Phone.256_assert_(featureLevel_ >= D3D_FEATURE_LEVEL_9_3);257258// Seems like a fair approximation...259caps_.dualSourceBlend = featureLevel_ >= D3D_FEATURE_LEVEL_10_0;260caps_.depthClampSupported = featureLevel_ >= D3D_FEATURE_LEVEL_10_0;261// SV_ClipDistance# seems to be 10+.262caps_.clipDistanceSupported = featureLevel_ >= D3D_FEATURE_LEVEL_10_0;263caps_.cullDistanceSupported = featureLevel_ >= D3D_FEATURE_LEVEL_10_0;264265caps_.depthRangeMinusOneToOne = false;266caps_.framebufferBlitSupported = false;267caps_.framebufferCopySupported = true;268caps_.framebufferDepthBlitSupported = false;269caps_.framebufferStencilBlitSupported = false;270caps_.framebufferDepthCopySupported = true;271caps_.framebufferSeparateDepthCopySupported = false; // Though could be emulated with a draw.272caps_.preferredDepthBufferFormat = DataFormat::D24_S8;273caps_.textureDepthSupported = true;274caps_.texture3DSupported = true;275caps_.fragmentShaderInt32Supported = true;276caps_.anisoSupported = true;277caps_.textureNPOTFullySupported = true;278caps_.fragmentShaderDepthWriteSupported = true;279caps_.fragmentShaderStencilWriteSupported = false;280caps_.blendMinMaxSupported = true;281caps_.multiSampleLevelsMask = 1; // More could be supported with some work.282283caps_.provokingVertexLast = false; // D3D has it first, unfortunately. (and no way to change it).284285caps_.presentInstantModeChange = true;286caps_.presentMaxInterval = 4;287caps_.presentModesSupported = PresentMode::FIFO | PresentMode::IMMEDIATE;288289D3D11_FEATURE_DATA_D3D11_OPTIONS options{};290HRESULT result = device_->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &options, sizeof(options));291if (SUCCEEDED(result)) {292if (options.OutputMergerLogicOp) {293// Actually, need to check that the format supports logic ops as well.294// Which normal UNORM formats don't seem to do in D3D11. So meh. We can't enable logicOp support.295// caps_.logicOpSupported = true;296}297}298299IDXGIDevice* dxgiDevice = nullptr;300IDXGIAdapter* adapter = nullptr;301HRESULT hr = device_->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void**>(&dxgiDevice));302if (SUCCEEDED(hr)) {303hr = dxgiDevice->GetAdapter(&adapter);304if (SUCCEEDED(hr)) {305DXGI_ADAPTER_DESC desc;306adapter->GetDesc(&desc);307adapterDesc_ = ConvertWStringToUTF8(desc.Description);308switch (desc.VendorId) {309case 0x10DE: caps_.vendor = GPUVendor::VENDOR_NVIDIA; break;310case 0x1002:311case 0x1022: caps_.vendor = GPUVendor::VENDOR_AMD; break;312case 0x163C:313case 0x8086:314case 0x8087: caps_.vendor = GPUVendor::VENDOR_INTEL; break;315// TODO: There are Windows ARM devices that could have Qualcomm here too.316// Not sure where I'll find the vendor codes for those though...317default:318caps_.vendor = GPUVendor::VENDOR_UNKNOWN;319}320caps_.deviceID = desc.DeviceId;321adapter->Release();322}323dxgiDevice->Release();324}325326caps_.isTilingGPU = false;327328// Hide D3D9 when we know it likely won't work well.329caps_.supportsD3D9 = true;330if (!strcmp(adapterDesc_.c_str(), "Intel(R) Iris(R) Xe Graphics")) {331caps_.supportsD3D9 = false;332}333334// Temp texture for read-back of small images. Custom textures are created on demand for larger ones.335// TODO: Should really benchmark if this extra complexity has any benefit.336D3D11_TEXTURE2D_DESC packDesc{};337packDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;338packDesc.BindFlags = 0;339packDesc.Width = 512;340packDesc.Height = 512;341packDesc.ArraySize = 1;342packDesc.MipLevels = 1;343packDesc.Usage = D3D11_USAGE_STAGING;344packDesc.SampleDesc.Count = 1;345packDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;346hr = device_->CreateTexture2D(&packDesc, nullptr, &packTexture_);347_assert_(SUCCEEDED(hr));348349shaderLanguageDesc_.Init(HLSL_D3D11);350351const size_t UP_MAX_BYTES = 65536 * 24;352353upBuffer_ = CreateBuffer(UP_MAX_BYTES, BufferUsageFlag::DYNAMIC | BufferUsageFlag::VERTEXDATA);354355IDXGIDevice1 *dxgiDevice1 = nullptr;356hr = device_->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast<void **>(&dxgiDevice1));357if (SUCCEEDED(hr)) {358caps_.setMaxFrameLatencySupported = true;359dxgiDevice1->SetMaximumFrameLatency(maxInflightFrames);360}361}362363D3D11DrawContext::~D3D11DrawContext() {364DestroyPresets();365366upBuffer_->Release();367packTexture_->Release();368369// Release references.370ID3D11RenderTargetView *view = nullptr;371context_->OMSetRenderTargets(1, &view, nullptr);372ID3D11ShaderResourceView *srv[2]{};373context_->PSSetShaderResources(0, 2, srv);374}375376void D3D11DrawContext::HandleEvent(Event ev, int width, int height, void *param1, void *param2) {377switch (ev) {378case Event::LOST_BACKBUFFER: {379if (curRenderTargetView_ == bbRenderTargetView_ || curDepthStencilView_ == bbDepthStencilView_) {380ID3D11RenderTargetView *view = nullptr;381context_->OMSetRenderTargets(1, &view, nullptr);382curRenderTargetView_ = nullptr;383curDepthStencilView_ = nullptr;384}385bbDepthStencilView_->Release();386bbDepthStencilView_ = nullptr;387bbDepthStencilTex_->Release();388bbDepthStencilTex_ = nullptr;389curRTWidth_ = 0;390curRTHeight_ = 0;391break;392}393case Event::GOT_BACKBUFFER: {394bbRenderTargetView_ = (ID3D11RenderTargetView *)param1;395bbRenderTargetTex_ = (ID3D11Texture2D *)param2;396bbWidth_ = width;397bbHeight_ = height;398399// Create matching depth stencil texture. This is not really needed for PPSSPP though,400// and probably not for most other renderers either as you're usually rendering to other render targets and401// then blitting them with a shader to the screen.402D3D11_TEXTURE2D_DESC descDepth{};403descDepth.Width = width;404descDepth.Height = height;405descDepth.MipLevels = 1;406descDepth.ArraySize = 1;407descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;408descDepth.SampleDesc.Count = 1;409descDepth.SampleDesc.Quality = 0;410descDepth.Usage = D3D11_USAGE_DEFAULT;411descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;412descDepth.CPUAccessFlags = 0;413descDepth.MiscFlags = 0;414HRESULT hr = device_->CreateTexture2D(&descDepth, nullptr, &bbDepthStencilTex_);415416// Create the depth stencil view417D3D11_DEPTH_STENCIL_VIEW_DESC descDSV{};418descDSV.Format = descDepth.Format;419descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;420descDSV.Texture2D.MipSlice = 0;421hr = device_->CreateDepthStencilView(bbDepthStencilTex_, &descDSV, &bbDepthStencilView_);422423context_->OMSetRenderTargets(1, &bbRenderTargetView_, bbDepthStencilView_);424425curRenderTargetView_ = bbRenderTargetView_;426curDepthStencilView_ = bbDepthStencilView_;427curRTWidth_ = width;428curRTHeight_ = height;429break;430}431}432}433434void D3D11DrawContext::EndFrame() {435// Fake a submit time.436frameTimeHistory_[frameCount_].firstSubmit = time_now_d();437curPipeline_ = nullptr;438}439440void D3D11DrawContext::Present(PresentMode presentMode, int vblanks) {441frameTimeHistory_[frameCount_].queuePresent = time_now_d();442443int interval = vblanks;444if (presentMode != PresentMode::FIFO) {445interval = 0;446}447// Safety for libretro448if (swapChain_) {449swapChain_->Present(interval, 0);450}451curRenderTargetView_ = nullptr;452curDepthStencilView_ = nullptr;453frameCount_++;454}455456void D3D11DrawContext::SetViewport(const Viewport &viewport) {457DisplayRect<float> rc{ viewport.TopLeftX , viewport.TopLeftY, viewport.Width, viewport.Height };458if (curRenderTargetView_ == bbRenderTargetView_) // Only the backbuffer is actually rotated wrong!459RotateRectToDisplay(rc, curRTWidth_, curRTHeight_);460D3D11_VIEWPORT vp;461vp.TopLeftX = rc.x;462vp.TopLeftY = rc.y;463vp.Width = rc.w;464vp.Height = rc.h;465vp.MinDepth = viewport.MinDepth;466vp.MaxDepth = viewport.MaxDepth;467context_->RSSetViewports(1, &vp);468}469470void D3D11DrawContext::SetScissorRect(int left, int top, int width, int height) {471_assert_(width >= 0);472_assert_(height >= 0);473DisplayRect<float> frc{ (float)left, (float)top, (float)width, (float)height };474if (curRenderTargetView_ == bbRenderTargetView_) // Only the backbuffer is actually rotated wrong!475RotateRectToDisplay(frc, curRTWidth_, curRTHeight_);476D3D11_RECT rc{};477rc.left = (INT)frc.x;478rc.top = (INT)frc.y;479rc.right = (INT)(frc.x + frc.w);480rc.bottom = (INT)(frc.y + frc.h);481context_->RSSetScissorRects(1, &rc);482}483484static const D3D11_COMPARISON_FUNC compareToD3D11[] = {485D3D11_COMPARISON_NEVER,486D3D11_COMPARISON_LESS,487D3D11_COMPARISON_EQUAL,488D3D11_COMPARISON_LESS_EQUAL,489D3D11_COMPARISON_GREATER,490D3D11_COMPARISON_NOT_EQUAL,491D3D11_COMPARISON_GREATER_EQUAL,492D3D11_COMPARISON_ALWAYS493};494495static const D3D11_STENCIL_OP stencilOpToD3D11[] = {496D3D11_STENCIL_OP_KEEP,497D3D11_STENCIL_OP_ZERO,498D3D11_STENCIL_OP_REPLACE,499D3D11_STENCIL_OP_INCR_SAT,500D3D11_STENCIL_OP_DECR_SAT,501D3D11_STENCIL_OP_INVERT,502D3D11_STENCIL_OP_INCR,503D3D11_STENCIL_OP_DECR,504};505506static DXGI_FORMAT dataFormatToD3D11(DataFormat format) {507switch (format) {508case DataFormat::R32_FLOAT: return DXGI_FORMAT_R32_FLOAT;509case DataFormat::R32G32_FLOAT: return DXGI_FORMAT_R32G32_FLOAT;510case DataFormat::R32G32B32_FLOAT: return DXGI_FORMAT_R32G32B32_FLOAT;511case DataFormat::R32G32B32A32_FLOAT: return DXGI_FORMAT_R32G32B32A32_FLOAT;512case DataFormat::A4R4G4B4_UNORM_PACK16: return DXGI_FORMAT_B4G4R4A4_UNORM;513case DataFormat::A1R5G5B5_UNORM_PACK16: return DXGI_FORMAT_B5G5R5A1_UNORM;514case DataFormat::R5G6B5_UNORM_PACK16: return DXGI_FORMAT_B5G6R5_UNORM;515case DataFormat::R8G8B8A8_UNORM: return DXGI_FORMAT_R8G8B8A8_UNORM;516case DataFormat::R8G8B8A8_UNORM_SRGB: return DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;517case DataFormat::B8G8R8A8_UNORM: return DXGI_FORMAT_B8G8R8A8_UNORM;518case DataFormat::B8G8R8A8_UNORM_SRGB: return DXGI_FORMAT_B8G8R8A8_UNORM_SRGB;519case DataFormat::R16_UNORM: return DXGI_FORMAT_R16_UNORM;520case DataFormat::R16_FLOAT: return DXGI_FORMAT_R16_FLOAT;521case DataFormat::R16G16_FLOAT: return DXGI_FORMAT_R16G16_FLOAT;522case DataFormat::R16G16B16A16_FLOAT: return DXGI_FORMAT_R16G16B16A16_FLOAT;523case DataFormat::D24_S8: return DXGI_FORMAT_D24_UNORM_S8_UINT;524case DataFormat::D16: return DXGI_FORMAT_D16_UNORM;525case DataFormat::D32F: return DXGI_FORMAT_D32_FLOAT;526case DataFormat::D32F_S8: return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;527case DataFormat::BC1_RGBA_UNORM_BLOCK: return DXGI_FORMAT_BC1_UNORM;528case DataFormat::BC2_UNORM_BLOCK: return DXGI_FORMAT_BC2_UNORM;529case DataFormat::BC3_UNORM_BLOCK: return DXGI_FORMAT_BC3_UNORM;530case DataFormat::BC4_UNORM_BLOCK: return DXGI_FORMAT_BC4_UNORM;531case DataFormat::BC5_UNORM_BLOCK: return DXGI_FORMAT_BC5_UNORM;532case DataFormat::BC7_UNORM_BLOCK: return DXGI_FORMAT_BC7_UNORM;533default:534return DXGI_FORMAT_UNKNOWN;535}536}537538static D3D11_PRIMITIVE_TOPOLOGY primToD3D11[] = {539D3D11_PRIMITIVE_TOPOLOGY_POINTLIST,540D3D11_PRIMITIVE_TOPOLOGY_LINELIST,541D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP,542D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST,543D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,544D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED,545// Tesselation shader only546D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST, // ???547// These are for geometry shaders only.548D3D11_PRIMITIVE_TOPOLOGY_LINELIST_ADJ,549D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ,550D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ,551D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ,552};553554inline void CopyStencilSide(D3D11_DEPTH_STENCILOP_DESC &side, const StencilSetup &input) {555side.StencilFunc = compareToD3D11[(int)input.compareOp];556side.StencilDepthFailOp = stencilOpToD3D11[(int)input.depthFailOp];557side.StencilFailOp = stencilOpToD3D11[(int)input.failOp];558side.StencilPassOp = stencilOpToD3D11[(int)input.passOp];559}560561static const D3D11_BLEND_OP blendOpToD3D11[] = {562D3D11_BLEND_OP_ADD,563D3D11_BLEND_OP_SUBTRACT,564D3D11_BLEND_OP_REV_SUBTRACT,565D3D11_BLEND_OP_MIN,566D3D11_BLEND_OP_MAX,567};568569static const D3D11_BLEND blendToD3D11[] = {570D3D11_BLEND_ZERO,571D3D11_BLEND_ONE,572D3D11_BLEND_SRC_COLOR,573D3D11_BLEND_INV_SRC_COLOR,574D3D11_BLEND_DEST_COLOR,575D3D11_BLEND_INV_DEST_COLOR,576D3D11_BLEND_SRC_ALPHA,577D3D11_BLEND_INV_SRC_ALPHA,578D3D11_BLEND_DEST_ALPHA,579D3D11_BLEND_INV_DEST_ALPHA,580D3D11_BLEND_BLEND_FACTOR,581D3D11_BLEND_INV_BLEND_FACTOR,582D3D11_BLEND_BLEND_FACTOR,583D3D11_BLEND_INV_BLEND_FACTOR,584D3D11_BLEND_SRC1_COLOR,585D3D11_BLEND_INV_SRC1_COLOR,586D3D11_BLEND_SRC1_ALPHA,587D3D11_BLEND_INV_SRC1_ALPHA,588};589590class D3D11BlendState : public BlendState {591public:592~D3D11BlendState() {593bs->Release();594}595ID3D11BlendState *bs;596float blendFactor[4];597};598599ID3D11DepthStencilState *D3D11DrawContext::GetCachedDepthStencilState(const D3D11DepthStencilState *state, uint8_t stencilWriteMask, uint8_t stencilCompareMask) {600D3D11DepthStencilKey key;601key.desc = state->desc;602key.writeMask = stencilWriteMask;603key.compareMask = stencilCompareMask;604605auto findResult = depthStencilCache_.find(key);606607if (findResult != depthStencilCache_.end()) {608return findResult->second;609}610611// OK, create and insert.612D3D11_DEPTH_STENCIL_DESC d3ddesc{};613d3ddesc.DepthEnable = state->desc.depthTestEnabled;614d3ddesc.DepthWriteMask = state->desc.depthWriteEnabled ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;615d3ddesc.DepthFunc = compareToD3D11[(int)state->desc.depthCompare];616d3ddesc.StencilEnable = state->desc.stencilEnabled;617d3ddesc.StencilReadMask = stencilCompareMask;618d3ddesc.StencilWriteMask = stencilWriteMask;619if (d3ddesc.StencilEnable) {620CopyStencilSide(d3ddesc.FrontFace, state->desc.stencil);621CopyStencilSide(d3ddesc.BackFace, state->desc.stencil);622}623624ID3D11DepthStencilState *dss = nullptr;625if (SUCCEEDED(device_->CreateDepthStencilState(&d3ddesc, &dss))) {626depthStencilCache_[key] = dss;627return dss;628} else {629return nullptr;630}631}632633DepthStencilState *D3D11DrawContext::CreateDepthStencilState(const DepthStencilStateDesc &desc) {634D3D11DepthStencilState *dss = new D3D11DepthStencilState();635dss->desc = desc;636return dynamic_cast<DepthStencilState *>(dss);637}638639BlendState *D3D11DrawContext::CreateBlendState(const BlendStateDesc &desc) {640D3D11BlendState *bs = new D3D11BlendState();641D3D11_BLEND_DESC d3ddesc{};642d3ddesc.AlphaToCoverageEnable = FALSE;643d3ddesc.IndependentBlendEnable = FALSE;644d3ddesc.RenderTarget[0].BlendEnable = desc.enabled;645d3ddesc.RenderTarget[0].RenderTargetWriteMask = desc.colorMask;646d3ddesc.RenderTarget[0].BlendOp = blendOpToD3D11[(int)desc.eqCol];647d3ddesc.RenderTarget[0].BlendOpAlpha = blendOpToD3D11[(int)desc.eqAlpha];648d3ddesc.RenderTarget[0].SrcBlend = blendToD3D11[(int)desc.srcCol];649d3ddesc.RenderTarget[0].SrcBlendAlpha = blendToD3D11[(int)desc.srcAlpha];650d3ddesc.RenderTarget[0].DestBlend = blendToD3D11[(int)desc.dstCol];651d3ddesc.RenderTarget[0].DestBlendAlpha = blendToD3D11[(int)desc.dstAlpha];652if (SUCCEEDED(device_->CreateBlendState(&d3ddesc, &bs->bs)))653return bs;654delete bs;655return nullptr;656}657658class D3D11RasterState : public RasterState {659public:660~D3D11RasterState() {661if (rs)662rs->Release();663}664ID3D11RasterizerState *rs;665};666667RasterState *D3D11DrawContext::CreateRasterState(const RasterStateDesc &desc) {668D3D11RasterState *rs = new D3D11RasterState();669D3D11_RASTERIZER_DESC d3ddesc{};670d3ddesc.FillMode = D3D11_FILL_SOLID;671switch (desc.cull) {672case CullMode::BACK: d3ddesc.CullMode = D3D11_CULL_BACK; break;673case CullMode::FRONT: d3ddesc.CullMode = D3D11_CULL_FRONT; break;674default:675case CullMode::NONE: d3ddesc.CullMode = D3D11_CULL_NONE; break;676}677d3ddesc.FrontCounterClockwise = desc.frontFace == Facing::CCW;678d3ddesc.ScissorEnable = true; // We always run with scissor enabled679d3ddesc.DepthClipEnable = true;680if (SUCCEEDED(device_->CreateRasterizerState(&d3ddesc, &rs->rs)))681return rs;682delete rs;683return nullptr;684}685686class D3D11SamplerState : public SamplerState {687public:688~D3D11SamplerState() {689if (ss)690ss->Release();691}692ID3D11SamplerState *ss = nullptr;693};694695static const D3D11_TEXTURE_ADDRESS_MODE taddrToD3D11[] = {696D3D11_TEXTURE_ADDRESS_WRAP,697D3D11_TEXTURE_ADDRESS_MIRROR,698D3D11_TEXTURE_ADDRESS_CLAMP,699D3D11_TEXTURE_ADDRESS_BORDER,700};701702SamplerState *D3D11DrawContext::CreateSamplerState(const SamplerStateDesc &desc) {703D3D11SamplerState *ss = new D3D11SamplerState();704D3D11_SAMPLER_DESC d3ddesc{};705d3ddesc.AddressU = taddrToD3D11[(int)desc.wrapU];706d3ddesc.AddressV = taddrToD3D11[(int)desc.wrapV];707d3ddesc.AddressW = taddrToD3D11[(int)desc.wrapW];708// TODO: Needs improvement709d3ddesc.Filter = desc.magFilter == TextureFilter::LINEAR ? D3D11_FILTER_MIN_MAG_MIP_LINEAR : D3D11_FILTER_MIN_MAG_MIP_POINT;710d3ddesc.MaxAnisotropy = 1.0f; // (UINT)desc.maxAniso;711d3ddesc.MinLOD = -FLT_MAX;712d3ddesc.MaxLOD = FLT_MAX;713d3ddesc.ComparisonFunc = compareToD3D11[(int)desc.shadowCompareFunc];714for (int i = 0; i < 4; i++) {715d3ddesc.BorderColor[i] = 1.0f;716}717if (SUCCEEDED(device_->CreateSamplerState(&d3ddesc, &ss->ss)))718return ss;719delete ss;720return nullptr;721}722723// Input layout creation is delayed to pipeline creation, as we need the vertex shader bytecode.724class D3D11InputLayout : public InputLayout {725public:726D3D11InputLayout() {}727InputLayoutDesc desc;728std::vector<D3D11_INPUT_ELEMENT_DESC> elements;729UINT stride; // type to match function parameter730};731732const char *semanticToD3D11(int semantic, UINT *index) {733*index = 0;734switch (semantic) {735case SEM_POSITION: return "POSITION";736case SEM_COLOR0: *index = 0; return "COLOR";737case SEM_COLOR1: *index = 1; return "COLOR";738case SEM_TEXCOORD0: *index = 0; return "TEXCOORD";739case SEM_TEXCOORD1: *index = 1; return "TEXCOORD";740case SEM_NORMAL: return "NORMAL";741case SEM_TANGENT: return "TANGENT";742case SEM_BINORMAL: return "BINORMAL"; // really BITANGENT743default: return "UNKNOWN";744}745}746747InputLayout *D3D11DrawContext::CreateInputLayout(const InputLayoutDesc &desc) {748D3D11InputLayout *inputLayout = new D3D11InputLayout();749inputLayout->desc = desc;750751// Translate to D3D11 elements;752for (size_t i = 0; i < desc.attributes.size(); i++) {753D3D11_INPUT_ELEMENT_DESC el;754el.AlignedByteOffset = desc.attributes[i].offset;755el.Format = dataFormatToD3D11(desc.attributes[i].format);756el.InstanceDataStepRate = 0;757el.InputSlot = 0;758el.SemanticName = semanticToD3D11(desc.attributes[i].location, &el.SemanticIndex);759el.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;760inputLayout->elements.push_back(el);761}762inputLayout->stride = desc.stride;763return inputLayout;764}765766class D3D11ShaderModule : public ShaderModule {767public:768D3D11ShaderModule(const std::string &tag) : tag_(tag) { }769~D3D11ShaderModule() {770if (vs)771vs->Release();772if (ps)773ps->Release();774if (gs)775gs->Release();776}777ShaderStage GetStage() const override { return stage; }778779std::vector<uint8_t> byteCode_;780ShaderStage stage;781std::string tag_;782783ID3D11VertexShader *vs = nullptr;784ID3D11PixelShader *ps = nullptr;785ID3D11GeometryShader *gs = nullptr;786};787788class D3D11Pipeline : public Pipeline {789public:790~D3D11Pipeline() {791if (il)792il->Release();793if (dynamicUniforms)794dynamicUniforms->Release();795for (D3D11ShaderModule *shaderModule : shaderModules) {796shaderModule->Release();797}798}799800AutoRef<D3D11InputLayout> input;801ID3D11InputLayout *il = nullptr;802AutoRef<D3D11BlendState> blend;803AutoRef<D3D11RasterState> raster;804805// Combined with dynamic state to key into cached D3D11DepthStencilState, to emulate dynamic parameters.806AutoRef<D3D11DepthStencilState> depthStencil;807808ID3D11VertexShader *vs = nullptr;809ID3D11PixelShader *ps = nullptr;810ID3D11GeometryShader *gs = nullptr;811D3D11_PRIMITIVE_TOPOLOGY topology = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED;812813std::vector<D3D11ShaderModule *> shaderModules;814815size_t dynamicUniformsSize = 0;816ID3D11Buffer *dynamicUniforms = nullptr;817};818819class D3D11Texture : public Texture {820public:821D3D11Texture(const TextureDesc &desc) {822width_ = desc.width;823height_ = desc.height;824depth_ = desc.depth;825format_ = desc.format;826mipLevels_ = desc.mipLevels;827}828~D3D11Texture() {829if (tex_)830tex_->Release();831if (stagingTex_)832stagingTex_->Release();833if (view_)834view_->Release();835}836837bool Create(ID3D11DeviceContext *context, ID3D11Device *device, const TextureDesc &desc, bool generateMips);838839bool CreateStagingTexture(ID3D11Device *device);840void UpdateTextureLevels(ID3D11DeviceContext *context, ID3D11Device *device, Texture *texture, const uint8_t *const *data, TextureCallback initDataCallback, int numLevels);841842ID3D11ShaderResourceView *View() { return view_; }843844private:845bool FillLevel(ID3D11DeviceContext *context, int level, int w, int h, int d, const uint8_t *const *data, TextureCallback initDataCallback);846847ID3D11Texture2D *tex_ = nullptr;848ID3D11Texture2D *stagingTex_ = nullptr;849ID3D11ShaderResourceView *view_ = nullptr;850int mipLevels_ = 0;851};852853bool D3D11Texture::FillLevel(ID3D11DeviceContext *context, int level, int w, int h, int d, const uint8_t *const *data, TextureCallback initDataCallback) {854D3D11_MAPPED_SUBRESOURCE mapped;855HRESULT hr = context->Map(stagingTex_, level, D3D11_MAP_WRITE, 0, &mapped);856if (!SUCCEEDED(hr)) {857tex_->Release();858tex_ = nullptr;859return false;860}861862if (!initDataCallback((uint8_t *)mapped.pData, data[level], w, h, d, mapped.RowPitch, mapped.DepthPitch)) {863for (int s = 0; s < d; ++s) {864for (int y = 0; y < h; ++y) {865void *dest = (uint8_t *)mapped.pData + mapped.DepthPitch * s + mapped.RowPitch * y;866uint32_t byteStride = w * (uint32_t)DataFormatSizeInBytes(format_);867const void *src = data[level] + byteStride * (y + h * s);868memcpy(dest, src, byteStride);869}870}871}872context->Unmap(stagingTex_, level);873return true;874}875876bool D3D11Texture::CreateStagingTexture(ID3D11Device *device) {877if (stagingTex_)878return true;879D3D11_TEXTURE2D_DESC descColor{};880descColor.Width = width_;881descColor.Height = height_;882descColor.MipLevels = mipLevels_;883descColor.ArraySize = 1;884descColor.Format = dataFormatToD3D11(format_);885descColor.SampleDesc.Count = 1;886descColor.SampleDesc.Quality = 0;887descColor.Usage = D3D11_USAGE_STAGING;888descColor.BindFlags = 0;889descColor.MiscFlags = 0;890descColor.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;891892HRESULT hr = device->CreateTexture2D(&descColor, nullptr, &stagingTex_);893if (!SUCCEEDED(hr)) {894stagingTex_->Release();895stagingTex_ = nullptr;896return false;897}898return true;899}900901bool D3D11Texture::Create(ID3D11DeviceContext *context, ID3D11Device *device, const TextureDesc &desc, bool generateMips) {902D3D11_TEXTURE2D_DESC descColor{};903descColor.Width = desc.width;904descColor.Height = desc.height;905descColor.MipLevels = desc.mipLevels;906descColor.ArraySize = 1;907descColor.Format = dataFormatToD3D11(desc.format);908descColor.SampleDesc.Count = 1;909descColor.SampleDesc.Quality = 0;910descColor.Usage = D3D11_USAGE_DEFAULT;911descColor.BindFlags = generateMips ? (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET) : D3D11_BIND_SHADER_RESOURCE;912descColor.MiscFlags = generateMips ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0;913descColor.CPUAccessFlags = 0;914915// Make sure we have a staging texture if we'll need it.916if (desc.initDataCallback && !CreateStagingTexture(device)) {917return false;918}919920D3D11_SUBRESOURCE_DATA *initDataParam = nullptr;921D3D11_SUBRESOURCE_DATA initData[12]{};922std::vector<uint8_t> initDataBuffer[12];923if (desc.initData.size() && !generateMips && !desc.initDataCallback) {924int w = desc.width;925int h = desc.height;926int d = desc.depth;927for (int i = 0; i < (int)desc.initData.size(); i++) {928uint32_t byteStride = w * (uint32_t)DataFormatSizeInBytes(desc.format);929initData[i].pSysMem = desc.initData[i];930initData[i].SysMemPitch = (UINT)byteStride;931initData[i].SysMemSlicePitch = (UINT)(h * byteStride);932w = (w + 1) / 2;933h = (h + 1) / 2;934d = (d + 1) / 2;935}936initDataParam = initData;937}938939HRESULT hr = device->CreateTexture2D(&descColor, initDataParam, &tex_);940if (!SUCCEEDED(hr)) {941tex_ = nullptr;942return false;943}944hr = device->CreateShaderResourceView(tex_, nullptr, &view_);945if (!SUCCEEDED(hr)) {946return false;947}948949if (generateMips && desc.initData.size() >= 1) {950if (desc.initDataCallback) {951if (!FillLevel(context, 0, desc.width, desc.height, desc.depth, desc.initData.data(), desc.initDataCallback)) {952tex_->Release();953return false;954}955956context->CopyResource(tex_, stagingTex_);957stagingTex_->Release();958stagingTex_ = nullptr;959} else {960uint32_t byteStride = desc.width * (uint32_t)DataFormatSizeInBytes(desc.format);961context->UpdateSubresource(tex_, 0, nullptr, desc.initData[0], byteStride, 0);962}963context->GenerateMips(view_);964} else if (desc.initDataCallback) {965int w = desc.width;966int h = desc.height;967int d = desc.depth;968for (int i = 0; i < (int)desc.initData.size(); i++) {969if (!FillLevel(context, i, w, h, d, desc.initData.data(), desc.initDataCallback)) {970if (i == 0) {971return false;972} else {973break;974}975}976977w = (w + 1) / 2;978h = (h + 1) / 2;979d = (d + 1) / 2;980}981982context->CopyResource(tex_, stagingTex_);983stagingTex_->Release();984stagingTex_ = nullptr;985}986return true;987}988989void D3D11Texture::UpdateTextureLevels(ID3D11DeviceContext *context, ID3D11Device *device, Texture *texture, const uint8_t * const*data, TextureCallback initDataCallback, int numLevels) {990if (!CreateStagingTexture(device)) {991return;992}993994int w = width_;995int h = height_;996int d = depth_;997for (int i = 0; i < (int)numLevels; i++) {998if (!FillLevel(context, i, w, h, d, data, initDataCallback)) {999break;1000}10011002w = (w + 1) / 2;1003h = (h + 1) / 2;1004d = (d + 1) / 2;1005}10061007context->CopyResource(tex_, stagingTex_);1008stagingTex_->Release();1009stagingTex_ = nullptr;1010}10111012Texture *D3D11DrawContext::CreateTexture(const TextureDesc &desc) {1013if (!(GetDataFormatSupport(desc.format) & FMT_TEXTURE)) {1014// D3D11 does not support this format as a texture format.1015return nullptr;1016}10171018D3D11Texture *tex = new D3D11Texture(desc);1019bool generateMips = desc.generateMips;1020if (desc.generateMips && !(GetDataFormatSupport(desc.format) & FMT_AUTOGEN_MIPS)) {1021// D3D11 does not support autogenerating mipmaps for this format.1022generateMips = false;1023}1024if (!tex->Create(context_, device_, desc, generateMips)) {1025tex->Release();1026return nullptr;1027}10281029return tex;1030}103110321033void D3D11DrawContext::UpdateTextureLevels(Texture *texture, const uint8_t **data, TextureCallback initDataCallback, int numLevels) {1034D3D11Texture *tex = (D3D11Texture *)texture;1035tex->UpdateTextureLevels(context_, device_, texture, data, initDataCallback, numLevels);1036}10371038ShaderModule *D3D11DrawContext::CreateShaderModule(ShaderStage stage, ShaderLanguage language, const uint8_t *data, size_t dataSize, const char *tag) {1039if (language != ShaderLanguage::HLSL_D3D11) {1040ERROR_LOG(Log::G3D, "Unsupported shader language");1041return nullptr;1042}10431044const char *vertexModel = "vs_4_0";1045const char *fragmentModel = "ps_4_0";1046const char *geometryModel = "gs_4_0";1047if (featureLevel_ <= D3D_FEATURE_LEVEL_9_3) {1048vertexModel = "vs_4_0_level_9_1";1049fragmentModel = "ps_4_0_level_9_1";1050geometryModel = nullptr;1051}10521053std::string compiled;1054std::string errors;1055const char *target = nullptr;1056switch (stage) {1057case ShaderStage::Fragment: target = fragmentModel; break;1058case ShaderStage::Vertex: target = vertexModel; break;1059case ShaderStage::Geometry:1060if (!geometryModel)1061return nullptr;1062target = geometryModel;1063break;1064case ShaderStage::Compute:1065default:1066Crash();1067break;1068}1069if (!target) {1070return nullptr;1071}10721073ID3DBlob *compiledCode = nullptr;1074ID3DBlob *errorMsgs = nullptr;1075int flags = D3DCOMPILE_ENABLE_BACKWARDS_COMPATIBILITY;1076HRESULT result = ptr_D3DCompile(data, dataSize, nullptr, nullptr, nullptr, "main", target, flags, 0, &compiledCode, &errorMsgs);1077if (compiledCode) {1078compiled = std::string((const char *)compiledCode->GetBufferPointer(), compiledCode->GetBufferSize());1079compiledCode->Release();1080}1081if (errorMsgs) {1082errors = std::string((const char *)errorMsgs->GetBufferPointer(), errorMsgs->GetBufferSize());1083ERROR_LOG(Log::G3D, "Failed compiling %s:\n%s\n%s", tag, data, errors.c_str());1084errorMsgs->Release();1085}10861087if (result != S_OK) {1088return nullptr;1089}10901091// OK, we can now proceed1092data = (const uint8_t *)compiled.c_str();1093dataSize = compiled.size();1094D3D11ShaderModule *module = new D3D11ShaderModule(tag);1095module->stage = stage;1096module->byteCode_ = std::vector<uint8_t>(data, data + dataSize);1097switch (stage) {1098case ShaderStage::Vertex:1099result = device_->CreateVertexShader(data, dataSize, nullptr, &module->vs);1100break;1101case ShaderStage::Fragment:1102result = device_->CreatePixelShader(data, dataSize, nullptr, &module->ps);1103break;1104case ShaderStage::Geometry:1105result = device_->CreateGeometryShader(data, dataSize, nullptr, &module->gs);1106break;1107default:1108ERROR_LOG(Log::G3D, "Unsupported shader stage");1109result = S_FALSE;1110break;1111}1112if (result == S_OK) {1113return module;1114} else {1115delete module;1116return nullptr;1117}1118return nullptr;1119}11201121Pipeline *D3D11DrawContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char *tag) {1122D3D11Pipeline *dPipeline = new D3D11Pipeline();1123dPipeline->blend = (D3D11BlendState *)desc.blend;1124dPipeline->depthStencil = (D3D11DepthStencilState *)desc.depthStencil;1125dPipeline->input = (D3D11InputLayout *)desc.inputLayout;1126dPipeline->raster = (D3D11RasterState *)desc.raster;1127dPipeline->topology = primToD3D11[(int)desc.prim];1128if (desc.uniformDesc) {1129dPipeline->dynamicUniformsSize = desc.uniformDesc->uniformBufferSize;1130D3D11_BUFFER_DESC bufdesc{};1131bufdesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;1132// We just round up to 16 here. If we get some garbage, that's fine.1133bufdesc.ByteWidth = ((UINT)dPipeline->dynamicUniformsSize + 15) & ~15;1134bufdesc.StructureByteStride = bufdesc.ByteWidth;1135bufdesc.Usage = D3D11_USAGE_DYNAMIC;1136bufdesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;1137HRESULT hr = device_->CreateBuffer(&bufdesc, nullptr, &dPipeline->dynamicUniforms);1138if (FAILED(hr)) {1139dPipeline->Release();1140return nullptr;1141}1142}11431144std::vector<D3D11ShaderModule *> shaders;1145D3D11ShaderModule *vshader = nullptr;1146for (auto iter : desc.shaders) {1147iter->AddRef();11481149D3D11ShaderModule *module = (D3D11ShaderModule *)iter;1150shaders.push_back(module);1151switch (module->GetStage()) {1152case ShaderStage::Vertex:1153vshader = module;1154dPipeline->vs = module->vs;1155break;1156case ShaderStage::Fragment:1157dPipeline->ps = module->ps;1158break;1159case ShaderStage::Geometry:1160dPipeline->gs = module->gs;1161break;1162}1163}1164dPipeline->shaderModules = shaders;11651166if (!vshader) {1167// No vertex shader - no graphics1168dPipeline->Release();1169return nullptr;1170}11711172// Can finally create the input layout1173if (dPipeline->input != nullptr) {1174const std::vector<D3D11_INPUT_ELEMENT_DESC> &elements = dPipeline->input->elements;1175HRESULT hr = device_->CreateInputLayout(elements.data(), (UINT)elements.size(), vshader->byteCode_.data(), vshader->byteCode_.size(), &dPipeline->il);1176if (!SUCCEEDED(hr)) {1177Crash();1178}1179} else {1180dPipeline->il = nullptr;1181}1182return dPipeline;1183}11841185void D3D11DrawContext::UpdateDynamicUniformBuffer(const void *ub, size_t size) {1186if (curPipeline_->dynamicUniformsSize != size) {1187Crash();1188}1189D3D11_MAPPED_SUBRESOURCE map{};1190context_->Map(curPipeline_->dynamicUniforms, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);1191memcpy(map.pData, ub, size);1192context_->Unmap(curPipeline_->dynamicUniforms, 0);1193}11941195void D3D11DrawContext::Invalidate(InvalidationFlags flags) {1196if (flags & InvalidationFlags::CACHED_RENDER_STATE) {1197// This is a signal to forget all our state caching.1198curBlend_ = nullptr;1199curDepthStencil_ = nullptr;1200curRaster_ = nullptr;1201curPS_ = nullptr;1202curVS_ = nullptr;1203curGS_ = nullptr;1204curInputLayout_ = nullptr;1205curTopology_ = D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED;1206curPipeline_ = nullptr;1207}1208}12091210void D3D11DrawContext::BindPipeline(Pipeline *pipeline) {1211D3D11Pipeline *dPipeline = (D3D11Pipeline *)pipeline;1212if (curPipeline_ == dPipeline)1213return;1214curPipeline_ = dPipeline;1215}12161217void D3D11DrawContext::ApplyCurrentState() {1218if (curBlend_ != curPipeline_->blend || blendFactorDirty_) {1219context_->OMSetBlendState(curPipeline_->blend->bs, blendFactor_, 0xFFFFFFFF);1220curBlend_ = curPipeline_->blend;1221blendFactorDirty_ = false;1222}1223if (curDepthStencil_ != curPipeline_->depthStencil || stencilDirty_) {1224ID3D11DepthStencilState *dss = GetCachedDepthStencilState(curPipeline_->depthStencil, stencilWriteMask_, stencilCompareMask_);1225context_->OMSetDepthStencilState(dss, stencilRef_);1226curDepthStencil_ = curPipeline_->depthStencil;1227stencilDirty_ = false;1228}1229if (curRaster_ != curPipeline_->raster) {1230context_->RSSetState(curPipeline_->raster->rs);1231curRaster_ = curPipeline_->raster;1232}1233if (curInputLayout_ != curPipeline_->il) {1234context_->IASetInputLayout(curPipeline_->il);1235curInputLayout_ = curPipeline_->il;1236}1237if (curVS_ != curPipeline_->vs) {1238context_->VSSetShader(curPipeline_->vs, nullptr, 0);1239curVS_ = curPipeline_->vs;1240}1241if (curPS_ != curPipeline_->ps) {1242context_->PSSetShader(curPipeline_->ps, nullptr, 0);1243curPS_ = curPipeline_->ps;1244}1245if (curGS_ != curPipeline_->gs) {1246context_->GSSetShader(curPipeline_->gs, nullptr, 0);1247curGS_ = curPipeline_->gs;1248}1249if (curTopology_ != curPipeline_->topology) {1250context_->IASetPrimitiveTopology(curPipeline_->topology);1251curTopology_ = curPipeline_->topology;1252}12531254if (curPipeline_->input != nullptr) {1255context_->IASetVertexBuffers(0, 1, &nextVertexBuffer_, &curPipeline_->input->stride, &nextVertexBufferOffset_);1256}1257if (dirtyIndexBuffer_) {1258context_->IASetIndexBuffer(nextIndexBuffer_, DXGI_FORMAT_R16_UINT, nextIndexBufferOffset_);1259dirtyIndexBuffer_ = false;1260}1261if (curPipeline_->dynamicUniforms) {1262context_->VSSetConstantBuffers(0, 1, &curPipeline_->dynamicUniforms);1263context_->PSSetConstantBuffers(0, 1, &curPipeline_->dynamicUniforms);1264}1265}12661267class D3D11Buffer : public Buffer {1268public:1269~D3D11Buffer() {1270if (buf)1271buf->Release();1272if (srView)1273srView->Release();1274}1275ID3D11Buffer *buf = nullptr;1276ID3D11ShaderResourceView *srView = nullptr;1277size_t size;1278};12791280Buffer *D3D11DrawContext::CreateBuffer(size_t size, uint32_t usageFlags) {1281D3D11Buffer *b = new D3D11Buffer();1282D3D11_BUFFER_DESC desc{};1283desc.ByteWidth = (UINT)size;1284desc.BindFlags = 0;1285if (usageFlags & VERTEXDATA)1286desc.BindFlags |= D3D11_BIND_VERTEX_BUFFER;1287if (usageFlags & INDEXDATA)1288desc.BindFlags |= D3D11_BIND_INDEX_BUFFER;1289if (usageFlags & UNIFORM)1290desc.BindFlags |= D3D11_BIND_CONSTANT_BUFFER;12911292desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;1293desc.Usage = D3D11_USAGE_DYNAMIC;12941295b->size = size;1296HRESULT hr = device_->CreateBuffer(&desc, nullptr, &b->buf);1297if (FAILED(hr)) {1298delete b;1299return nullptr;1300}1301return b;1302}13031304void D3D11DrawContext::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offset, size_t size, UpdateBufferFlags flags) {1305D3D11Buffer *buf = (D3D11Buffer *)buffer;1306if ((flags & UPDATE_DISCARD) || (offset == 0 && size == buf->size)) {1307// Can just discard the old contents. This is only allowed for DYNAMIC buffers.1308D3D11_MAPPED_SUBRESOURCE map;1309context_->Map(buf->buf, 0, D3D11_MAP_WRITE_DISCARD, 0, &map);1310memcpy(map.pData, data, size);1311context_->Unmap(buf->buf, 0);1312return;1313}13141315// Should probably avoid this case.1316D3D11_BOX box{};1317box.left = (UINT)offset;1318box.right = (UINT)(offset + size);1319box.bottom = 1;1320box.back = 1;1321context_->UpdateSubresource(buf->buf, 0, &box, data, 0, 0);1322}13231324void D3D11DrawContext::BindVertexBuffer(Buffer *buffer, int offset) {1325// Lazy application1326D3D11Buffer *buf = (D3D11Buffer *)buffer;1327nextVertexBuffer_ = buf->buf;1328nextVertexBufferOffset_ = offset;1329}13301331void D3D11DrawContext::BindIndexBuffer(Buffer *indexBuffer, int offset) {1332D3D11Buffer *buf = (D3D11Buffer *)indexBuffer;1333// Lazy application1334dirtyIndexBuffer_ = true;1335nextIndexBuffer_ = buf ? buf->buf : 0;1336nextIndexBufferOffset_ = buf ? offset : 0;1337}13381339void D3D11DrawContext::Draw(int vertexCount, int offset) {1340ApplyCurrentState();1341context_->Draw(vertexCount, offset);1342}13431344void D3D11DrawContext::DrawIndexed(int indexCount, int offset) {1345ApplyCurrentState();1346context_->DrawIndexed(indexCount, offset, 0);1347}13481349void D3D11DrawContext::DrawUP(const void *vdata, int vertexCount) {1350ApplyCurrentState();13511352int byteSize = vertexCount * curPipeline_->input->stride;13531354UpdateBuffer(upBuffer_, (const uint8_t *)vdata, 0, byteSize, Draw::UPDATE_DISCARD);1355BindVertexBuffer(upBuffer_, 0);1356int offset = 0;1357Draw(vertexCount, offset);1358}13591360uint32_t D3D11DrawContext::GetDataFormatSupport(DataFormat fmt) const {1361DXGI_FORMAT giFmt = dataFormatToD3D11(fmt);1362if (giFmt == DXGI_FORMAT_UNKNOWN)1363return 0;1364UINT giSupport = 0;1365HRESULT result = device_->CheckFormatSupport(giFmt, &giSupport);1366if (FAILED(result))1367return 0;1368uint32_t support = 0;1369if (giSupport & D3D11_FORMAT_SUPPORT_TEXTURE2D)1370support |= FMT_TEXTURE;1371if (giSupport & D3D11_FORMAT_SUPPORT_RENDER_TARGET)1372support |= FMT_RENDERTARGET;1373if (giSupport & D3D11_FORMAT_SUPPORT_IA_VERTEX_BUFFER)1374support |= FMT_INPUTLAYOUT;1375if (giSupport & D3D11_FORMAT_SUPPORT_DEPTH_STENCIL)1376support |= FMT_DEPTHSTENCIL;1377if (giSupport & D3D11_FORMAT_SUPPORT_MIP_AUTOGEN)1378support |= FMT_AUTOGEN_MIPS;1379return support;1380}13811382// A D3D11Framebuffer is a D3D11Framebuffer plus all the textures it owns.1383class D3D11Framebuffer : public Framebuffer {1384public:1385D3D11Framebuffer(int width, int height) {1386width_ = width;1387height_ = height;1388}1389~D3D11Framebuffer() {1390if (colorTex)1391colorTex->Release();1392if (colorRTView)1393colorRTView->Release();1394if (colorSRView)1395colorSRView->Release();1396if (depthSRView)1397depthSRView->Release();1398if (depthStencilTex)1399depthStencilTex->Release();1400if (depthStencilRTView)1401depthStencilRTView->Release();1402}14031404ID3D11Texture2D *colorTex = nullptr;1405ID3D11RenderTargetView *colorRTView = nullptr;1406ID3D11ShaderResourceView *colorSRView = nullptr;1407ID3D11ShaderResourceView *depthSRView = nullptr;1408DXGI_FORMAT colorFormat = DXGI_FORMAT_UNKNOWN;14091410ID3D11Texture2D *depthStencilTex = nullptr;1411ID3D11DepthStencilView *depthStencilRTView = nullptr;1412DXGI_FORMAT depthStencilFormat = DXGI_FORMAT_UNKNOWN;1413};14141415Framebuffer *D3D11DrawContext::CreateFramebuffer(const FramebufferDesc &desc) {1416HRESULT hr;1417D3D11Framebuffer *fb = new D3D11Framebuffer(desc.width, desc.height);14181419// We don't (yet?) support multiview for D3D11. Not sure if there's a way to do it.1420// Texture arrays are supported but we don't have any other use cases yet.1421_dbg_assert_(desc.numLayers == 1);14221423fb->colorFormat = DXGI_FORMAT_R8G8B8A8_UNORM;1424D3D11_TEXTURE2D_DESC descColor{};1425descColor.Width = desc.width;1426descColor.Height = desc.height;1427descColor.MipLevels = 1;1428descColor.ArraySize = 1;1429descColor.Format = fb->colorFormat;1430descColor.SampleDesc.Count = 1;1431descColor.SampleDesc.Quality = 0;1432descColor.Usage = D3D11_USAGE_DEFAULT;1433descColor.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;1434descColor.CPUAccessFlags = 0;1435descColor.MiscFlags = 0;1436hr = device_->CreateTexture2D(&descColor, nullptr, &fb->colorTex);1437if (FAILED(hr)) {1438delete fb;1439return nullptr;1440}1441hr = device_->CreateRenderTargetView(fb->colorTex, nullptr, &fb->colorRTView);1442if (FAILED(hr)) {1443delete fb;1444return nullptr;1445}1446hr = device_->CreateShaderResourceView(fb->colorTex, nullptr, &fb->colorSRView);1447if (FAILED(hr)) {1448delete fb;1449return nullptr;1450}14511452if (desc.z_stencil) {1453fb->depthStencilFormat = DXGI_FORMAT_D24_UNORM_S8_UINT;1454D3D11_TEXTURE2D_DESC descDepth{};1455descDepth.Width = desc.width;1456descDepth.Height = desc.height;1457descDepth.MipLevels = 1;1458descDepth.ArraySize = 1;1459descDepth.Format = DXGI_FORMAT_R24G8_TYPELESS; // so we can create an R24X8 view of it.1460descDepth.SampleDesc.Count = 1;1461descDepth.SampleDesc.Quality = 0;1462descDepth.Usage = D3D11_USAGE_DEFAULT;1463descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;1464descDepth.CPUAccessFlags = 0;1465descDepth.MiscFlags = 0;1466hr = device_->CreateTexture2D(&descDepth, nullptr, &fb->depthStencilTex);1467if (FAILED(hr)) {1468delete fb;1469return nullptr;1470}1471D3D11_DEPTH_STENCIL_VIEW_DESC descDSV{};1472descDSV.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;1473descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;1474descDSV.Texture2D.MipSlice = 0;1475hr = device_->CreateDepthStencilView(fb->depthStencilTex, &descDSV, &fb->depthStencilRTView);1476if (FAILED(hr)) {1477delete fb;1478return nullptr;1479}14801481D3D11_SHADER_RESOURCE_VIEW_DESC depthViewDesc{};1482depthViewDesc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS;1483depthViewDesc.Texture2D.MostDetailedMip = 0;1484depthViewDesc.Texture2D.MipLevels = 1;1485depthViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;1486hr = device_->CreateShaderResourceView(fb->depthStencilTex, &depthViewDesc, &fb->depthSRView);1487if (FAILED(hr)) {1488WARN_LOG(Log::G3D, "Failed to create SRV for depth buffer.");1489fb->depthSRView = nullptr;1490}1491}14921493return fb;1494}14951496void D3D11DrawContext::BindTextures(int start, int count, Texture **textures, TextureBindFlags flags) {1497// Collect the resource views from the textures.1498ID3D11ShaderResourceView *views[MAX_BOUND_TEXTURES];1499_assert_(start + count <= ARRAY_SIZE(views));1500for (int i = 0; i < count; i++) {1501D3D11Texture *tex = (D3D11Texture *)textures[i];1502views[i] = tex ? tex->View() : nullptr;1503}1504context_->PSSetShaderResources(start, count, views);1505}15061507void D3D11DrawContext::BindNativeTexture(int index, void *nativeTexture) {1508// Collect the resource views from the textures.1509ID3D11ShaderResourceView *view = (ID3D11ShaderResourceView *)nativeTexture;1510context_->PSSetShaderResources(index, 1, &view);1511}15121513void D3D11DrawContext::BindSamplerStates(int start, int count, SamplerState **states) {1514ID3D11SamplerState *samplers[MAX_BOUND_TEXTURES];1515_assert_(start + count <= ARRAY_SIZE(samplers));1516for (int i = 0; i < count; i++) {1517D3D11SamplerState *samp = (D3D11SamplerState *)states[i];1518samplers[i] = samp ? samp->ss : nullptr;1519}1520context_->PSSetSamplers(start, count, samplers);1521}15221523void D3D11DrawContext::Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) {1524if ((mask & FBChannel::FB_COLOR_BIT) && curRenderTargetView_) {1525float colorRGBA[4];1526Uint8x4ToFloat4(colorRGBA, colorval);1527context_->ClearRenderTargetView(curRenderTargetView_, colorRGBA);1528}1529if ((mask & (FBChannel::FB_DEPTH_BIT | FBChannel::FB_STENCIL_BIT)) && curDepthStencilView_) {1530UINT clearFlag = 0;1531if (mask & FBChannel::FB_DEPTH_BIT)1532clearFlag |= D3D11_CLEAR_DEPTH;1533if (mask & FBChannel::FB_STENCIL_BIT)1534clearFlag |= D3D11_CLEAR_STENCIL;1535context_->ClearDepthStencilView(curDepthStencilView_, clearFlag, depthVal, stencilVal);1536}1537}15381539void D3D11DrawContext::BeginFrame(DebugFlags debugFlags) {1540FrameTimeData &frameTimeData = frameTimeHistory_.Add(frameCount_);1541frameTimeData.afterFenceWait = time_now_d();1542frameTimeData.frameBegin = frameTimeData.afterFenceWait;15431544context_->OMSetRenderTargets(1, &curRenderTargetView_, curDepthStencilView_);15451546if (curBlend_ != nullptr) {1547context_->OMSetBlendState(curBlend_->bs, blendFactor_, 0xFFFFFFFF);1548}1549if (curDepthStencil_ != nullptr) {1550context_->OMSetDepthStencilState(GetCachedDepthStencilState(curDepthStencil_, stencilWriteMask_, stencilCompareMask_), stencilRef_);1551}1552if (curRaster_ != nullptr) {1553context_->RSSetState(curRaster_->rs);1554}1555context_->IASetInputLayout(curInputLayout_);1556context_->VSSetShader(curVS_, nullptr, 0);1557context_->PSSetShader(curPS_, nullptr, 0);1558context_->GSSetShader(curGS_, nullptr, 0);1559if (curTopology_ != D3D11_PRIMITIVE_TOPOLOGY_UNDEFINED) {1560context_->IASetPrimitiveTopology(curTopology_);1561}1562if (curPipeline_ != nullptr) {1563context_->IASetVertexBuffers(0, 1, &nextVertexBuffer_, &curPipeline_->input->stride, &nextVertexBufferOffset_);1564context_->IASetIndexBuffer(nextIndexBuffer_, DXGI_FORMAT_R16_UINT, nextIndexBufferOffset_);1565if (curPipeline_->dynamicUniforms) {1566context_->VSSetConstantBuffers(0, 1, &curPipeline_->dynamicUniforms);1567context_->PSSetConstantBuffers(0, 1, &curPipeline_->dynamicUniforms);1568}1569}1570}15711572void D3D11DrawContext::CopyFramebufferImage(Framebuffer *srcfb, int level, int x, int y, int z, Framebuffer *dstfb, int dstLevel, int dstX, int dstY, int dstZ, int width, int height, int depth, int channelBit, const char *tag) {1573D3D11Framebuffer *src = (D3D11Framebuffer *)srcfb;1574D3D11Framebuffer *dst = (D3D11Framebuffer *)dstfb;15751576ID3D11Texture2D *srcTex = nullptr;1577ID3D11Texture2D *dstTex = nullptr;1578switch (channelBit) {1579case FBChannel::FB_COLOR_BIT:1580srcTex = src->colorTex;1581dstTex = dst->colorTex;1582break;1583case FBChannel::FB_DEPTH_BIT:1584srcTex = src->depthStencilTex;1585dstTex = dst->depthStencilTex;1586break;1587}1588_assert_(srcTex && dstTex);15891590// TODO: Check for level too!1591if (width == src->Width() && width == dst->Width() && height == src->Height() && height == dst->Height() && x == 0 && y == 0 && z == 0 && dstX == 0 && dstY == 0 && dstZ == 0) {1592// Don't need to specify region. This might be faster, too.1593context_->CopyResource(dstTex, srcTex);1594return;1595}15961597if (channelBit != FBChannel::FB_DEPTH_BIT) {1598// Non-full copies are not supported for the depth channel.1599// Note that we need to clip the source box.1600if (x < 0) {1601width += x; // note that x is negative1602dstX -= x;1603x = 0;1604}1605if (y < 0) {1606height += y; // note that y is negative1607dstY -= y;1608y = 0;1609}1610if (x + width > src->Width()) {1611width = src->Width() - x;1612}1613if (y + height > src->Height()) {1614height = src->Height() - y;1615}1616D3D11_BOX srcBox{ (UINT)x, (UINT)y, (UINT)z, (UINT)(x + width), (UINT)(y + height), (UINT)(z + depth) };1617context_->CopySubresourceRegion(dstTex, dstLevel, dstX, dstY, dstZ, srcTex, level, &srcBox);1618}1619}16201621bool D3D11DrawContext::BlitFramebuffer(Framebuffer *srcfb, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *dstfb, int dstX1, int dstY1, int dstX2, int dstY2, int channelBits, FBBlitFilter filter, const char *tag) {1622// Unfortunately D3D11 has no equivalent to this, gotta render a quad. Well, in some cases we can issue a copy instead.1623Crash();1624return false;1625}16261627bool D3D11DrawContext::CopyFramebufferToMemory(Framebuffer *src, int channelBits, int bx, int by, int bw, int bh, Draw::DataFormat destFormat, void *pixels, int pixelStride, ReadbackMode mode, const char *tag) {1628D3D11Framebuffer *fb = (D3D11Framebuffer *)src;16291630if (fb) {1631_assert_(fb->colorFormat == DXGI_FORMAT_R8G8B8A8_UNORM);16321633// TODO: Figure out where the badness really comes from.1634if (bx + bw > fb->Width()) {1635bw -= (bx + bw) - fb->Width();1636}1637if (by + bh > fb->Height()) {1638bh -= (by + bh) - fb->Height();1639}1640}16411642if (bh <= 0 || bw <= 0)1643return true;16441645bool useGlobalPacktex = (bx + bw <= 512 && by + bh <= 512) && channelBits == FB_COLOR_BIT;16461647ID3D11Texture2D *packTex = nullptr;1648if (!useGlobalPacktex) {1649D3D11_TEXTURE2D_DESC packDesc{};1650packDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;1651packDesc.BindFlags = 0;1652packDesc.Width = bw;1653packDesc.Height = bh;1654packDesc.ArraySize = 1;1655packDesc.MipLevels = 1;1656packDesc.Usage = D3D11_USAGE_STAGING;1657packDesc.SampleDesc.Count = 1;1658switch (channelBits) {1659case FB_COLOR_BIT:1660packDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // TODO: fb->colorFormat;1661break;1662case FB_DEPTH_BIT:1663case FB_STENCIL_BIT:1664if (!fb) {1665// Not supported.1666return false;1667}1668packDesc.Format = fb->depthStencilFormat;1669break;1670default:1671_assert_(false);1672}1673device_->CreateTexture2D(&packDesc, nullptr, &packTex);1674} else {1675switch (channelBits) {1676case FB_DEPTH_BIT:1677case FB_STENCIL_BIT:1678if (!fb)1679return false;1680default:1681break;1682}1683packTex = packTexture_;1684}16851686if (!packTex)1687return false;16881689D3D11_BOX srcBox{ (UINT)bx, (UINT)by, 0, (UINT)(bx + bw), (UINT)(by + bh), 1 };1690DataFormat srcFormat = DataFormat::UNDEFINED;1691switch (channelBits) {1692case FB_COLOR_BIT:1693context_->CopySubresourceRegion(packTex, 0, bx, by, 0, fb ? fb->colorTex : bbRenderTargetTex_, 0, &srcBox);1694srcFormat = DataFormat::R8G8B8A8_UNORM;1695break;1696case FB_DEPTH_BIT:1697case FB_STENCIL_BIT:1698// For depth/stencil buffers, we can't reliably copy subrectangles, so just copy the whole resource.1699_assert_(fb); // Can't copy depth/stencil from backbuffer. Shouldn't happen thanks to checks above.1700context_->CopyResource(packTex, fb->depthStencilTex);1701srcFormat = Draw::DataFormat::D24_S8;1702break;1703default:1704_assert_(false);1705break;1706}17071708// Ideally, we'd round robin between two packTexture_, and simply use the other one. Though if the game1709// does a once-off copy, that won't work at all.17101711// BIG GPU STALL1712D3D11_MAPPED_SUBRESOURCE map;1713HRESULT result = context_->Map(packTex, 0, D3D11_MAP_READ, 0, &map);1714if (FAILED(result)) {1715return false;1716}17171718const size_t srcByteOffset = by * map.RowPitch + bx * DataFormatSizeInBytes(srcFormat);1719const uint8_t *srcWithOffset = (const uint8_t *)map.pData + srcByteOffset;1720switch (channelBits) {1721case FB_COLOR_BIT:1722// Pixel size always 4 here because we always request BGRA8888.1723ConvertFromRGBA8888((uint8_t *)pixels, srcWithOffset, pixelStride, map.RowPitch / sizeof(uint32_t), bw, bh, destFormat);1724break;1725case FB_DEPTH_BIT:1726if (srcFormat == destFormat) {1727// Can just memcpy when it matches no matter the format!1728uint8_t *dst = (uint8_t *)pixels;1729const uint8_t *src = (const uint8_t *)srcWithOffset;1730for (int y = 0; y < bh; ++y) {1731memcpy(dst, src, bw * DataFormatSizeInBytes(srcFormat));1732dst += pixelStride * DataFormatSizeInBytes(srcFormat);1733src += map.RowPitch;1734}1735} else if (destFormat == DataFormat::D32F) {1736ConvertToD32F((uint8_t *)pixels, srcWithOffset, pixelStride, map.RowPitch / sizeof(uint32_t), bw, bh, srcFormat);1737} else if (destFormat == DataFormat::D16) {1738ConvertToD16((uint8_t *)pixels, srcWithOffset, pixelStride, map.RowPitch / sizeof(uint32_t), bw, bh, srcFormat);1739} else {1740_assert_(false);1741}1742break;1743case FB_STENCIL_BIT:1744if (srcFormat == destFormat) {1745// Can just memcpy when it matches no matter the format!1746uint8_t *dst = (uint8_t *)pixels;1747const uint8_t *src = (const uint8_t *)srcWithOffset;1748for (int y = 0; y < bh; ++y) {1749memcpy(dst, src, bw * DataFormatSizeInBytes(srcFormat));1750dst += pixelStride * DataFormatSizeInBytes(srcFormat);1751src += map.RowPitch;1752}1753} else if (destFormat == DataFormat::S8) {1754for (int y = 0; y < bh; y++) {1755uint8_t *destStencil = (uint8_t *)pixels + y * pixelStride;1756const uint32_t *src = (const uint32_t *)(srcWithOffset + map.RowPitch * y);1757for (int x = 0; x < bw; x++) {1758destStencil[x] = src[x] >> 24;1759}1760}1761} else {1762_assert_(false);1763}1764break;1765}17661767context_->Unmap(packTex, 0);17681769if (!useGlobalPacktex) {1770packTex->Release();1771}1772return true;1773}17741775void D3D11DrawContext::BindFramebufferAsRenderTarget(Framebuffer *fbo, const RenderPassInfo &rp, const char *tag) {1776// TODO: deviceContext1 can actually discard. Useful on Windows Mobile.1777if (fbo) {1778D3D11Framebuffer *fb = (D3D11Framebuffer *)fbo;1779if (curRenderTargetView_ == fb->colorRTView && curDepthStencilView_ == fb->depthStencilRTView) {1780// No need to switch, but let's fallthrough to clear!1781} else {1782// It's not uncommon that the first slot happens to have the new render target bound as a texture,1783// so unbind to make the validation layers happy.1784ID3D11ShaderResourceView *empty[1] = {};1785context_->PSSetShaderResources(0, ARRAY_SIZE(empty), empty);1786context_->OMSetRenderTargets(1, &fb->colorRTView, fb->depthStencilRTView);1787curRenderTargetView_ = fb->colorRTView;1788curDepthStencilView_ = fb->depthStencilRTView;1789curRTWidth_ = fb->Width();1790curRTHeight_ = fb->Height();1791}1792curRenderTarget_ = fb;1793} else {1794if (curRenderTargetView_ == bbRenderTargetView_ && curDepthStencilView_ == bbDepthStencilView_) {1795// No need to switch, but let's fallthrough to clear!1796} else {1797context_->OMSetRenderTargets(1, &bbRenderTargetView_, bbDepthStencilView_);1798curRenderTargetView_ = bbRenderTargetView_;1799curDepthStencilView_ = bbDepthStencilView_;1800curRTWidth_ = bbWidth_;1801curRTHeight_ = bbHeight_;1802}1803curRenderTarget_ = nullptr;1804}1805if (rp.color == RPAction::CLEAR && curRenderTargetView_) {1806float cv[4]{};1807if (rp.clearColor)1808Uint8x4ToFloat4(cv, rp.clearColor);1809context_->ClearRenderTargetView(curRenderTargetView_, cv);1810}1811int mask = 0;1812if (rp.depth == RPAction::CLEAR) {1813mask |= D3D11_CLEAR_DEPTH;1814}1815if (rp.stencil == RPAction::CLEAR) {1816mask |= D3D11_CLEAR_STENCIL;1817}1818if (mask && curDepthStencilView_) {1819context_->ClearDepthStencilView(curDepthStencilView_, mask, rp.clearDepth, rp.clearStencil);1820}18211822if (invalidationCallback_) {1823invalidationCallback_(InvalidationCallbackFlags::RENDER_PASS_STATE);1824}1825}18261827void D3D11DrawContext::BindFramebufferAsTexture(Framebuffer *fbo, int binding, FBChannel channelBit, int layer) {1828_dbg_assert_(binding < MAX_BOUND_TEXTURES);1829_dbg_assert_(layer == ALL_LAYERS || layer == 0); // No multiple layer support on D3D1830D3D11Framebuffer *fb = (D3D11Framebuffer *)fbo;1831switch (channelBit) {1832case FBChannel::FB_COLOR_BIT:1833context_->PSSetShaderResources(binding, 1, &fb->colorSRView);1834break;1835case FBChannel::FB_DEPTH_BIT:1836if (fb->depthSRView) {1837context_->PSSetShaderResources(binding, 1, &fb->depthSRView);1838}1839break;1840default:1841break;1842}1843}18441845uint64_t D3D11DrawContext::GetNativeObject(NativeObject obj, void *srcObject) {1846switch (obj) {1847case NativeObject::DEVICE:1848return (uint64_t)(uintptr_t)device_;1849case NativeObject::CONTEXT:1850return (uint64_t)(uintptr_t)context_;1851case NativeObject::DEVICE_EX:1852return (uint64_t)(uintptr_t)device1_;1853case NativeObject::CONTEXT_EX:1854return (uint64_t)(uintptr_t)context1_;1855case NativeObject::BACKBUFFER_COLOR_TEX:1856return (uint64_t)(uintptr_t)bbRenderTargetTex_;1857case NativeObject::BACKBUFFER_DEPTH_TEX:1858return (uint64_t)(uintptr_t)bbDepthStencilTex_;1859case NativeObject::BACKBUFFER_COLOR_VIEW:1860return (uint64_t)(uintptr_t)bbRenderTargetView_;1861case NativeObject::BACKBUFFER_DEPTH_VIEW:1862return (uint64_t)(uintptr_t)bbDepthStencilView_;1863case NativeObject::FEATURE_LEVEL:1864return (uint64_t)(uintptr_t)featureLevel_;1865case NativeObject::TEXTURE_VIEW:1866return (uint64_t)(((D3D11Texture *)srcObject)->View());1867default:1868return 0;1869}1870}18711872void D3D11DrawContext::GetFramebufferDimensions(Framebuffer *fbo, int *w, int *h) {1873D3D11Framebuffer *fb = (D3D11Framebuffer *)fbo;1874if (fb) {1875*w = fb->Width();1876*h = fb->Height();1877} else {1878*w = bbWidth_;1879*h = bbHeight_;1880}1881}18821883DrawContext *T3DCreateD3D11Context(ID3D11Device *device, ID3D11DeviceContext *context, ID3D11Device1 *device1, ID3D11DeviceContext1 *context1, IDXGISwapChain *swapChain, D3D_FEATURE_LEVEL featureLevel, HWND hWnd, const std::vector<std::string> &adapterNames, int maxInflightFrames) {1884return new D3D11DrawContext(device, context, device1, context1, swapChain, featureLevel, hWnd, adapterNames, maxInflightFrames);1885}18861887} // namespace Draw188818891890