Swap chains, part 2 (#94)

This commit is contained in:
Kai Ninomiya
2017-07-27 18:30:57 -07:00
committed by GitHub
parent 3818e18c5c
commit c16a67ae52
49 changed files with 771 additions and 435 deletions

View File

@@ -28,6 +28,7 @@
#include "backend/RenderPipeline.h"
#include "backend/Sampler.h"
#include "backend/ShaderModule.h"
#include "backend/SwapChain.h"
#include "backend/Texture.h"
#include <unordered_set>
@@ -130,6 +131,9 @@ namespace backend {
ShaderModuleBuilder* DeviceBase::CreateShaderModuleBuilder() {
return new ShaderModuleBuilder(this);
}
SwapChainBuilder* DeviceBase::CreateSwapChainBuilder() {
return new SwapChainBuilder(this);
}
TextureBuilder* DeviceBase::CreateTextureBuilder() {
return new TextureBuilder(this);
}

View File

@@ -26,6 +26,8 @@ namespace backend {
}
SwapChainBase::~SwapChainBase() {
const auto& im = GetImplementation();
im.Destroy(im.userData);
}
DeviceBase* SwapChainBase::GetDevice() {
@@ -41,6 +43,8 @@ namespace backend {
this->format = format;
this->width = width;
this->height = height;
implementation.Configure(implementation.userData,
static_cast<nxtTextureFormat>(format), width, height);
}
TextureBase* SwapChainBase::GetNextTexture() {
@@ -102,7 +106,7 @@ namespace backend {
nxtSwapChainImplementation& impl = *reinterpret_cast<nxtSwapChainImplementation*>(implementation);
if (!impl.Init || impl.Destroy || !impl.Configure ||
if (!impl.Init || !impl.Destroy || !impl.Configure ||
!impl.GetNextTexture || !impl.Present) {
HandleError("Implementation is incomplete");
return;

View File

@@ -61,7 +61,7 @@ namespace d3d12 {
{
auto* view = ToBackend(GetBindingAsTextureView(binding));
auto& srv = view->GetSRVDescriptor();
d3d12Device->CreateShaderResourceView(ToBackend(view->GetTexture())->GetD3D12Resource().Get(), &srv, cbvUavSrvHeapStart.GetCPUHandle(*cbvUavSrvHeapOffset + bindingOffsets[binding]));
d3d12Device->CreateShaderResourceView(ToBackend(view->GetTexture())->GetD3D12Resource(), &srv, cbvUavSrvHeapStart.GetCPUHandle(*cbvUavSrvHeapOffset + bindingOffsets[binding]));
}
break;
case nxt::BindingType::Sampler:

View File

@@ -309,7 +309,7 @@ namespace d3d12 {
);
D3D12_TEXTURE_COPY_LOCATION textureLocation;
textureLocation.pResource = texture->GetD3D12Resource().Get();
textureLocation.pResource = texture->GetD3D12Resource();
textureLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
textureLocation.SubresourceIndex = copy->destination.level;
@@ -358,7 +358,7 @@ namespace d3d12 {
);
D3D12_TEXTURE_COPY_LOCATION textureLocation;
textureLocation.pResource = texture->GetD3D12Resource().Get();
textureLocation.pResource = texture->GetD3D12Resource();
textureLocation.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;
textureLocation.SubresourceIndex = copy->source.level;

View File

@@ -51,11 +51,6 @@ namespace d3d12 {
return backendDevice->GetCommandQueue();
}
void SetNextTexture(nxtDevice device, ComPtr<ID3D12Resource> resource) {
Device* backendDevice = reinterpret_cast<Device*>(device);
backendDevice->SetNextTexture(resource);
}
uint64_t GetSerial(const nxtDevice device) {
const Device* backendDevice = reinterpret_cast<const Device*>(device);
return backendDevice->GetSerial();
@@ -101,6 +96,8 @@ namespace d3d12 {
ASSERT_SUCCESS(d3d12Device->CreateFence(serial, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence)));
fenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
ASSERT(fenceEvent != nullptr);
NextSerial();
}
Device::~Device() {
@@ -163,15 +160,6 @@ namespace d3d12 {
return pendingCommands.commandList;
}
ComPtr<ID3D12Resource> Device::GetCurrentTexture() {
return nextTexture;
}
void Device::SetNextTexture(ComPtr<ID3D12Resource> resource) {
nextTexture = resource;
}
void Device::TickImpl() {
// Perform cleanup operations to free unused objects
const uint64_t lastCompletedSerial = fence->GetCompletedValue();

View File

@@ -120,9 +120,6 @@ namespace d3d12 {
void OpenCommandList(ComPtr<ID3D12GraphicsCommandList>* commandList);
ComPtr<ID3D12GraphicsCommandList> GetPendingCommandList();
ComPtr<ID3D12Resource> GetCurrentTexture();
void SetNextTexture(ComPtr<ID3D12Resource> resource);
uint64_t GetSerial() const;
void NextSerial();
void WaitForSerial(uint64_t serial);
@@ -147,8 +144,6 @@ namespace d3d12 {
ComPtr<ID3D12GraphicsCommandList> commandList;
bool open = false;
} pendingCommands;
ComPtr<ID3D12Resource> nextTexture;
};
class DepthStencilState : public DepthStencilStateBase {

View File

@@ -78,20 +78,7 @@ namespace d3d12 {
for (uint32_t index : IterateBitSet(subpassInfo.colorAttachmentsSet)) {
uint32_t heapIndex = attachmentHeapIndices[subpassInfo.colorAttachments[index]];
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = rtvHeap.GetCPUHandle(heapIndex);
uint32_t attachment = subpassInfo.colorAttachments[index];
if (!GetTextureView(attachment)) {
// TODO(kainino@chromium.org): null=backbuffer hack
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc;
rtvDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D;
rtvDesc.Texture2D.MipSlice = 0;
rtvDesc.Texture2D.PlaneSlice = 0;
device->GetD3D12Device()->CreateRenderTargetView(device->GetCurrentTexture().Get(), &rtvDesc, rtvHandle);
}
args.RTVs[args.numRTVs++] = rtvHandle;
args.RTVs[args.numRTVs++] = rtvHeap.GetCPUHandle(heapIndex);
}
if (subpassInfo.depthStencilAttachmentSet) {
uint32_t heapIndex = attachmentHeapIndices[subpassInfo.depthStencilAttachment];

View File

@@ -14,6 +14,7 @@
#include "backend/d3d12/SwapChainD3D12.h"
#include "backend/d3d12/D3D12Backend.h"
#include "backend/d3d12/TextureD3D12.h"
#include <nxt/nxt_wsi.h>
@@ -25,19 +26,23 @@ namespace d3d12 {
: SwapChainBase(builder) {
const auto& im = GetImplementation();
nxtWSIContextD3D12 wsiContext = {};
// TODO(kainino@chromium.org): set up wsiContext
wsiContext.device = reinterpret_cast<nxtDevice>(GetDevice());
im.Init(im.userData, &wsiContext);
// TODO(kainino@chromium.org): set up D3D12 swapchain
}
SwapChain::~SwapChain() {
// TODO(kainino@chromium.org): clean up D3D12 swapchain
}
TextureBase* SwapChain::GetNextTextureImpl(TextureBuilder* builder) {
ComPtr<ID3D12Resource> nativeTexture = nullptr;
// TODO(kainino@chromium.org): obtain native texture from D3D12 swapchain
const auto& im = GetImplementation();
nxtSwapChainNextTexture next = {};
nxtSwapChainError error = im.GetNextTexture(im.userData, &next);
if (error) {
GetDevice()->HandleError(error);
return nullptr;
}
ID3D12Resource* nativeTexture = reinterpret_cast<ID3D12Resource*>(next.texture);
return new Texture(builder, nativeTexture);
}

View File

@@ -105,23 +105,28 @@ namespace d3d12 {
resourceDescriptor.Flags = D3D12ResourceFlags(GetAllowedUsage(), GetFormat());
resource = device->GetResourceAllocator()->Allocate(D3D12_HEAP_TYPE_DEFAULT, resourceDescriptor, D3D12TextureUsage(GetUsage(), GetFormat()));
resourcePtr = resource.Get();
}
Texture::Texture(TextureBuilder* builder, ComPtr<ID3D12Resource> nativeTexture)
: TextureBase(builder), device(ToBackend(builder->GetDevice())), resource(nativeTexture) {
// With this constructor, the lifetime of the ID3D12Resource is externally managed.
Texture::Texture(TextureBuilder* builder, ID3D12Resource* nativeTexture)
: TextureBase(builder), device(ToBackend(builder->GetDevice())),
resourcePtr(nativeTexture) {
}
Texture::~Texture() {
// TODO(kainino@chromium.org): Maybe don't release when using the native texture constructor?
device->GetResourceAllocator()->Release(resource);
if (resource) {
// If we own the resource, release it.
device->GetResourceAllocator()->Release(resource);
}
}
DXGI_FORMAT Texture::GetD3D12Format() const {
return D3D12TextureFormat(GetFormat());
}
ComPtr<ID3D12Resource> Texture::GetD3D12Resource() {
return resource;
ID3D12Resource* Texture::GetD3D12Resource() {
return resourcePtr;
}
bool Texture::GetResourceTransitionBarrier(nxt::TextureUsageBit currentUsage, nxt::TextureUsageBit targetUsage, D3D12_RESOURCE_BARRIER* barrier) {
@@ -134,7 +139,7 @@ namespace d3d12 {
barrier->Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier->Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrier->Transition.pResource = resource.Get();
barrier->Transition.pResource = resourcePtr;
barrier->Transition.StateBefore = stateBefore;
barrier->Transition.StateAfter = stateAfter;
barrier->Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;

View File

@@ -29,16 +29,17 @@ namespace d3d12 {
class Texture : public TextureBase {
public:
Texture(TextureBuilder* builder);
Texture(TextureBuilder* builder, ComPtr<ID3D12Resource> nativeTexture);
Texture(TextureBuilder* builder, ID3D12Resource* nativeTexture);
~Texture();
DXGI_FORMAT GetD3D12Format() const;
ComPtr<ID3D12Resource> GetD3D12Resource();
ID3D12Resource* GetD3D12Resource();
bool GetResourceTransitionBarrier(nxt::TextureUsageBit currentUsage, nxt::TextureUsageBit targetUsage, D3D12_RESOURCE_BARRIER* barrier);
private:
Device* device;
ComPtr<ID3D12Resource> resource;
ComPtr<ID3D12Resource> resource = {};
ID3D12Resource* resourcePtr = nullptr;
// NXT API
void TransitionUsageImpl(nxt::TextureUsageBit currentUsage, nxt::TextureUsageBit targetUsage) override;

View File

@@ -90,15 +90,8 @@ namespace metal {
for (uint32_t index = 0; index < info.colorAttachments.size(); ++index) {
uint32_t attachment = info.colorAttachments[index];
// TODO(kainino@chromium.org): currently a 'null' texture view
// falls back to the 'back buffer' but this should go away
// when we have WSI.
id<MTLTexture> texture = nil;
if (auto textureView = currentFramebuffer->GetTextureView(attachment)) {
texture = ToBackend(textureView->GetTexture())->GetMTLTexture();
} else {
texture = device->GetCurrentTexture();
}
auto textureView = currentFramebuffer->GetTextureView(attachment);
auto texture = ToBackend(textureView->GetTexture())->GetMTLTexture();
descriptor.colorAttachments[index].texture = texture;
descriptor.colorAttachments[index].loadAction = MTLLoadActionLoad;
descriptor.colorAttachments[index].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 0.0);

View File

@@ -109,11 +109,7 @@ namespace metal {
void TickImpl() override;
void SetNextDrawable(id<CAMetalDrawable> drawable);
void Present();
id<MTLDevice> GetMTLDevice();
id<MTLTexture> GetCurrentTexture();
id<MTLCommandBuffer> GetPendingCommandBuffer();
void SubmitPendingCommandBuffer();
@@ -130,9 +126,6 @@ namespace metal {
MapReadRequestTracker* mapReadTracker;
ResourceUploader* resourceUploader;
id<CAMetalDrawable> currentDrawable = nil;
id<MTLTexture> currentTexture = nil;
Serial finishedCommandSerial = 0;
Serial pendingCommandSerial = 1;
id<MTLCommandBuffer> pendingCommands = nil;

View File

@@ -41,16 +41,6 @@ namespace metal {
*device = reinterpret_cast<nxtDevice>(new Device(metalDevice));
}
void SetNextDrawable(nxtDevice device, id<CAMetalDrawable> drawable) {
Device* backendDevice = reinterpret_cast<Device*>(device);
backendDevice->SetNextDrawable(drawable);
}
void Present(nxtDevice device) {
Device* backendDevice = reinterpret_cast<Device*>(device);
backendDevice->Present();
}
// Device
Device::Device(id<MTLDevice> mtlDevice)
@@ -86,9 +76,6 @@ namespace metal {
[commandQueue release];
commandQueue = nil;
[currentTexture release];
currentTexture = nil;
}
BindGroupBase* Device::CreateBindGroup(BindGroupBuilder* builder) {
@@ -155,43 +142,10 @@ namespace metal {
SubmitPendingCommandBuffer();
}
void Device::SetNextDrawable(id<CAMetalDrawable> drawable) {
[currentDrawable release];
currentDrawable = drawable;
[currentDrawable retain];
[currentTexture release];
currentTexture = drawable.texture;
[currentTexture retain];
MTLRenderPassDescriptor* passDescriptor = [MTLRenderPassDescriptor renderPassDescriptor];
passDescriptor.colorAttachments[0].texture = currentTexture;
passDescriptor.colorAttachments[0].loadAction = MTLLoadActionClear;
passDescriptor.colorAttachments[0].storeAction = MTLStoreActionStore;
passDescriptor.colorAttachments[0].clearColor = MTLClearColorMake(0.0, 0.0, 0.0, 1.0);
id<MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];
id<MTLRenderCommandEncoder> commandEncoder = [commandBuffer
renderCommandEncoderWithDescriptor:passDescriptor];
[commandEncoder endEncoding];
[commandBuffer commit];
}
void Device::Present() {
id<MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];
[commandBuffer presentDrawable: currentDrawable];
[commandBuffer commit];
}
id<MTLDevice> Device::GetMTLDevice() {
return mtlDevice;
}
id<MTLTexture> Device::GetCurrentTexture() {
return currentTexture;
}
id<MTLCommandBuffer> Device::GetPendingCommandBuffer() {
if (pendingCommands == nil) {
pendingCommands = [commandQueue commandBuffer];

View File

@@ -14,6 +14,7 @@
#include "backend/metal/SwapChainMTL.h"
#include "backend/metal/MetalBackend.h"
#include "backend/metal/TextureMTL.h"
#include <nxt/nxt_wsi.h>
@@ -25,19 +26,23 @@ namespace metal {
: SwapChainBase(builder) {
const auto& im = GetImplementation();
nxtWSIContextMetal wsiContext = {};
// TODO(kainino@chromium.org): set up wsiContext
wsiContext.device = ToBackend(GetDevice())->GetMTLDevice();
im.Init(im.userData, &wsiContext);
// TODO(kainino@chromium.org): set up Metal swapchain
}
SwapChain::~SwapChain() {
// TODO(kainino@chromium.org): clean up Metal swapchain
}
TextureBase* SwapChain::GetNextTextureImpl(TextureBuilder* builder) {
id<MTLTexture> nativeTexture = nil;
// TODO(kainino@chromium.org): obtain MTLTexture from Metal swapchain
const auto& im = GetImplementation();
nxtSwapChainNextTexture next = {};
nxtSwapChainError error = im.GetNextTexture(im.userData, &next);
if (error) {
GetDevice()->HandleError(error);
return nullptr;
}
id<MTLTexture> nativeTexture = reinterpret_cast<id<MTLTexture>>(next.texture);
return new Texture(builder, nativeTexture);
}

View File

@@ -104,21 +104,13 @@ namespace opengl {
glGenFramebuffers(1, &currentFBO);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, currentFBO);
auto* device = ToBackend(GetDevice());
const auto& info = currentRenderPass->GetSubpassInfo(currentSubpass);
for (uint32_t index = 0; index < info.colorAttachments.size(); ++index) {
uint32_t attachment = info.colorAttachments[index];
// TODO(kainino@chromium.org): currently a 'null' texture view
// falls back to the 'back buffer' but this should go away
// when we have WSI.
GLuint texture = 0;
if (auto textureView = currentFramebuffer->GetTextureView(attachment)) {
texture = ToBackend(textureView->GetTexture())->GetHandle();
} else {
texture = device->GetCurrentTexture();
}
auto textureView = currentFramebuffer->GetTextureView(attachment);
GLuint texture = ToBackend(textureView->GetTexture())->GetHandle();
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0 + index,
GL_TEXTURE_2D, texture, 0);
@@ -131,6 +123,7 @@ namespace opengl {
nxt::TextureFormat format = textureView->GetTexture()->GetFormat();
GLenum glAttachment = 0;
// TODO(kainino@chromium.org): it may be valid to just always use GL_DEPTH_STENCIL_ATTACHMENT here.
if (TextureFormatHasDepth(format)) {
if (TextureFormatHasStencil(format)) {
glAttachment = GL_DEPTH_STENCIL_ATTACHMENT;

View File

@@ -30,11 +30,6 @@ namespace opengl {
nxtProcTable GetNonValidatingProcs();
nxtProcTable GetValidatingProcs();
void HACKCLEAR(nxtDevice device) {
Device* backendDevice = reinterpret_cast<Device*>(device);
backendDevice->HACKCLEAR();
}
void Init(void* (*getProc)(const char*), nxtProcTable* procs, nxtDevice* device) {
*device = nullptr;
@@ -44,17 +39,6 @@ namespace opengl {
*device = reinterpret_cast<nxtDevice>(new Device);
glEnable(GL_DEPTH_TEST);
HACKCLEAR(*device);
}
void InitBackbuffer(nxtDevice device) {
Device* backendDevice = reinterpret_cast<Device*>(device);
backendDevice->InitBackbuffer();
}
void CommitBackbuffer(nxtDevice device) {
Device* backendDevice = reinterpret_cast<Device*>(device);
backendDevice->CommitBackbuffer();
}
// Device
@@ -117,36 +101,6 @@ namespace opengl {
void Device::TickImpl() {
}
void Device::HACKCLEAR() {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, backFBO);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
}
void Device::InitBackbuffer() {
glGenTextures(1, &backTexture);
glBindTexture(GL_TEXTURE_2D, backTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 640, 480, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glGenFramebuffers(1, &backFBO);
glBindFramebuffer(GL_READ_FRAMEBUFFER, backFBO);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, backTexture, 0);
HACKCLEAR();
}
void Device::CommitBackbuffer() {
glBindFramebuffer(GL_READ_FRAMEBUFFER, backFBO);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, 640, 480, 0, 0, 640, 480,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
}
GLuint Device::GetCurrentTexture() {
return backTexture;
}
// Bind Group
BindGroup::BindGroup(BindGroupBuilder* builder)

View File

@@ -104,15 +104,6 @@ namespace opengl {
TextureViewBase* CreateTextureView(TextureViewBuilder* builder) override;
void TickImpl() override;
void HACKCLEAR();
void InitBackbuffer();
void CommitBackbuffer();
GLuint GetCurrentTexture();
private:
GLuint backFBO = 0;
GLuint backTexture = 0;
};
class BindGroup : public BindGroupBase {

View File

@@ -14,6 +14,7 @@
#include "backend/opengl/SwapChainGL.h"
#include "backend/Device.h"
#include "backend/opengl/TextureGL.h"
#include <nxt/nxt_wsi.h>
@@ -24,18 +25,21 @@ namespace opengl {
SwapChain::SwapChain(SwapChainBuilder* builder)
: SwapChainBase(builder) {
const auto& im = GetImplementation();
nxtWSIContextGL wsiContext = {};
// TODO(kainino@chromium.org): set up wsiContext
im.Init(im.userData, &wsiContext);
// TODO(kainino@chromium.org): set up FBO
im.Init(im.userData, nullptr);
}
SwapChain::~SwapChain() {
// TODO(kainino@chromium.org): clean up FBO
}
TextureBase* SwapChain::GetNextTextureImpl(TextureBuilder* builder) {
const auto& im = GetImplementation();
nxtSwapChainNextTexture next = {};
nxtSwapChainError error = im.GetNextTexture(im.userData, &next);
if (error) {
GetDevice()->HandleError(error);
return nullptr;
}
GLuint nativeTexture = static_cast<GLuint>(reinterpret_cast<uintptr_t>(next.texture));
return new Texture(builder, nativeTexture);
}

View File

@@ -31,9 +31,6 @@ namespace opengl {
protected:
TextureBase* GetNextTextureImpl(TextureBuilder* builder) override;
private:
GLuint nativeTexture = 0;
};
}