/* Copyright 2021 flyinghead This file is part of Flycast. Flycast 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. Flycast 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 Flycast. If not, see . */ #pragma once #include "../dx11context.h" class Buffers { public: void init(ComPtr device, ComPtr deviceContext) { this->device = device; this->deviceContext = deviceContext; pixelsBufferView.reset(); pixelsBuffer.reset(); D3D11_BUFFER_DESC desc{}; desc.ByteWidth = (UINT)std::min(config::PixelBufferSize, UINT_MAX); desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = D3D11_BIND_UNORDERED_ACCESS; desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; desc.StructureByteStride = 16; // sizeof(struct Pixel) HRESULT hr = device->CreateBuffer(&desc, nullptr, &pixelsBuffer.get()); if (FAILED(hr)) { if (desc.ByteWidth > D3D11_REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_C_TERM * 1024u * 1024u) { desc.ByteWidth = D3D11_REQ_RESOURCE_SIZE_IN_MEGABYTES_EXPRESSION_C_TERM * 1024u * 1024u; hr = device->CreateBuffer(&desc, nullptr, &pixelsBuffer.get()); } if (FAILED(hr)) { WARN_LOG(RENDERER, "Pixels buffer creation failed: %x", hr); return; } } D3D11_UNORDERED_ACCESS_VIEW_DESC uaView{}; uaView.Format = DXGI_FORMAT_UNKNOWN; uaView.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; uaView.Buffer.FirstElement = 0; uaView.Buffer.Flags = D3D11_BUFFER_UAV_FLAG_COUNTER; uaView.Buffer.NumElements = desc.ByteWidth / desc.StructureByteStride; hr = device->CreateUnorderedAccessView(pixelsBuffer, &uaView, &pixelsBufferView.get()); if (FAILED(hr)) WARN_LOG(RENDERER, "Pixels buffer UAV creation failed: %x", hr); } void resize(int width, int height) { if (this->width >= width && this->height >= height) return; this->width = std::max(this->width, width); this->height = std::max(this->height, height); abufferPointersView.reset(); abufferPointersTex.reset(); D3D11_TEXTURE2D_DESC desc{}; desc.Width = this->width; desc.Height = this->height; desc.ArraySize = 1; desc.SampleDesc.Count = 1; desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS; desc.Format = DXGI_FORMAT_R32_UINT; desc.MipLevels = 1; D3D11_SUBRESOURCE_DATA initialData{}; initialData.SysMemPitch = this->width * sizeof(int); initialData.pSysMem = malloc(initialData.SysMemPitch * this->height); memset((void *)initialData.pSysMem, 0xff, initialData.SysMemPitch * this->height); HRESULT hr = device->CreateTexture2D(&desc, &initialData, &abufferPointersTex.get()); free((void *)initialData.pSysMem); if (FAILED(hr)) { WARN_LOG(RENDERER, "A-buffer texture creation failed: %x", hr); return; } D3D11_UNORDERED_ACCESS_VIEW_DESC uaView{}; uaView.Format = DXGI_FORMAT_UNKNOWN; uaView.ViewDimension = D3D11_UAV_DIMENSION_TEXTURE2D; hr = device->CreateUnorderedAccessView(abufferPointersTex, &uaView, &abufferPointersView.get()); if (FAILED(hr)) WARN_LOG(RENDERER, "A-buffer texture UAV creation failed: %x", hr); } void bind() { ID3D11UnorderedAccessView *uavs[] { pixelsBufferView, abufferPointersView }; UINT initialCounts[] { 0, (UINT)-1 }; deviceContext->OMSetRenderTargetsAndUnorderedAccessViews(D3D11_KEEP_RENDER_TARGETS_AND_DEPTH_STENCIL, nullptr, nullptr, 1, std::size(uavs), uavs, initialCounts); } void term() { width = 0; height = 0; abufferPointersView.reset(); abufferPointersTex.reset(); pixelsBufferView.reset(); pixelsBuffer.reset(); deviceContext.reset(); device.reset(); } private: int width = 0; int height = 0; ComPtr device; ComPtr deviceContext; ComPtr abufferPointersTex; ComPtr abufferPointersView; ComPtr pixelsBuffer; ComPtr pixelsBufferView; };