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

@@ -15,6 +15,8 @@
#ifndef UTILS_BACKENDBINDING_H_
#define UTILS_BACKENDBINDING_H_
#include <nxt/nxt_wsi.h>
struct GLFWwindow;
typedef struct nxtProcTable_s nxtProcTable;
typedef struct nxtDeviceImpl* nxtDevice;
@@ -35,7 +37,7 @@ namespace utils {
virtual void SetupGLFWWindowHints() = 0;
virtual void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) = 0;
virtual void SwapBuffers() = 0;
virtual uint64_t GetSwapChainImplementation() = 0;
void SetWindow(GLFWwindow* window);

View File

@@ -19,6 +19,7 @@ list(APPEND UTILS_SOURCES
${UTILS_DIR}/BackendBinding.h
${UTILS_DIR}/NXTHelpers.cpp
${UTILS_DIR}/NXTHelpers.h
${UTILS_DIR}/SwapChainImpl.h
${UTILS_DIR}/SystemUtils.cpp
${UTILS_DIR}/SystemUtils.h
)

View File

@@ -15,6 +15,8 @@
#include "utils/BackendBinding.h"
#include "common/Assert.h"
#include "nxt/nxt_wsi.h"
#include "utils/SwapChainImpl.h"
#define GLFW_EXPOSE_NATIVE_WIN32
#include "GLFW/glfw3.h"
@@ -34,7 +36,6 @@ namespace backend {
namespace d3d12 {
void Init(ComPtr<ID3D12Device> d3d12Device, nxtProcTable* procs, nxtDevice* device);
ComPtr<ID3D12CommandQueue> GetCommandQueue(nxtDevice device);
void SetNextTexture(nxtDevice device, ComPtr<ID3D12Resource> resource);
uint64_t GetSerial(const nxtDevice device);
void NextSerial(nxtDevice device);
void ExecuteCommandLists(nxtDevice device, std::initializer_list<ID3D12CommandList*> commandLists);
@@ -44,48 +45,88 @@ namespace d3d12 {
}
namespace utils {
namespace {
void ASSERT_SUCCESS(HRESULT hr) {
ASSERT(SUCCEEDED(hr));
}
class D3D12Binding : public BackendBinding {
public:
void SetupGLFWWindowHints() override {
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
}
ComPtr<IDXGIFactory4> CreateFactory() {
ComPtr<IDXGIFactory4> factory;
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
uint32_t dxgiFactoryFlags = 0;
uint32_t dxgiFactoryFlags = 0;
#ifdef _DEBUG
// Enable the debug layer (requires the Graphics Tools "optional feature").
// NOTE: Enabling the debug layer after device creation will invalidate the active device.
{
ComPtr<ID3D12Debug> debugController;
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) {
debugController->EnableDebugLayer();
// Enable the debug layer (requires the Graphics Tools "optional feature").
// NOTE: Enabling the debug layer after device creation will invalidate the active device.
{
ComPtr<ID3D12Debug> debugController;
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController)))) {
debugController->EnableDebugLayer();
// Enable additional debug layers.
dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
}
ComPtr<IDXGIDebug1> dxgiDebug;
if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(&dxgiDebug)))) {
dxgiDebug->ReportLiveObjects(DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_FLAGS(DXGI_DEBUG_RLO_ALL));
}
// Enable additional debug layers.
dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
}
ComPtr<IDXGIDebug1> dxgiDebug;
if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(&dxgiDebug)))) {
dxgiDebug->ReportLiveObjects(DXGI_DEBUG_ALL, DXGI_DEBUG_RLO_FLAGS(DXGI_DEBUG_RLO_ALL));
}
}
#endif
ASSERT_SUCCESS(CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&factory)));
ASSERT(GetHardwareAdapter(factory.Get(), &hardwareAdapter));
ASSERT_SUCCESS(D3D12CreateDevice(
hardwareAdapter.Get(),
D3D_FEATURE_LEVEL_11_0,
IID_PPV_ARGS(&d3d12Device)
));
ASSERT_SUCCESS(CreateDXGIFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&factory)));
backend::d3d12::Init(d3d12Device, procs, device);
backendDevice = *device;
return factory;
}
}
class SwapChainImplD3D12 : SwapChainImpl {
public:
static nxtSwapChainImplementation Create(HWND window, const nxtProcTable& procs) {
auto impl = GenerateSwapChainImplementation<SwapChainImplD3D12, nxtWSIContextD3D12>();
impl.userData = new SwapChainImplD3D12(window, procs);
return impl;
}
private:
nxtDevice backendDevice = nullptr;
nxtProcTable procs = {};
static constexpr unsigned int kFrameCount = 2;
HWND window = 0;
ComPtr<IDXGIFactory4> factory = {};
ComPtr<ID3D12CommandQueue> commandQueue = {};
ComPtr<IDXGISwapChain3> swapChain = {};
ComPtr<ID3D12Resource> renderTargetResources[kFrameCount] = {};
// Frame synchronization. Updated every frame
uint32_t renderTargetIndex = 0;
uint32_t previousRenderTargetIndex = 0;
uint64_t lastSerialRenderTargetWasUsed[kFrameCount] = {};
SwapChainImplD3D12(HWND window, nxtProcTable procs)
: window(window), procs(procs), factory(CreateFactory()) {
}
~SwapChainImplD3D12() {
}
// For GenerateSwapChainImplementation
friend class SwapChainImpl;
void Init(nxtWSIContextD3D12* ctx) {
backendDevice = ctx->device;
commandQueue = backend::d3d12::GetCommandQueue(backendDevice);
}
nxtSwapChainError Configure(nxtTextureFormat format,
uint32_t width, uint32_t height) {
if (format != NXT_TEXTURE_FORMAT_R8_G8_B8_A8_UNORM) {
return "unsupported format";
}
ASSERT(width > 0);
ASSERT(height > 0);
int width, height;
glfwGetWindowSize(window, &width, &height);
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
swapChainDesc.Width = width;
swapChainDesc.Height = height;
@@ -96,11 +137,10 @@ namespace utils {
swapChainDesc.SampleDesc.Count = 1;
swapChainDesc.SampleDesc.Quality = 0;
HWND win32Window = glfwGetWin32Window(window);
ComPtr<IDXGISwapChain1> swapChain1;
ASSERT_SUCCESS(factory->CreateSwapChainForHwnd(
commandQueue.Get(),
win32Window,
window,
&swapChainDesc,
nullptr,
nullptr,
@@ -122,48 +162,26 @@ namespace utils {
lastSerialRenderTargetWasUsed[n] = initialSerial;
}
// Transition the first frame to be a render target
{
backend::d3d12::OpenCommandList(backendDevice, &commandList);
D3D12_RESOURCE_BARRIER resourceBarrier;
resourceBarrier.Transition.pResource = renderTargetResources[renderTargetIndex].Get();
resourceBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
resourceBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
resourceBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
resourceBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
resourceBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
commandList->ResourceBarrier(1, &resourceBarrier);
ASSERT_SUCCESS(commandList->Close());
backend::d3d12::ExecuteCommandLists(backendDevice, { commandList.Get() });
backend::d3d12::NextSerial(backendDevice);
}
backend::d3d12::SetNextTexture(backendDevice, renderTargetResources[renderTargetIndex]);
return NXT_SWAP_CHAIN_NO_ERROR;
}
void SwapBuffers() override {
// Transition current frame's render target for presenting
{
backend::d3d12::OpenCommandList(backendDevice, &commandList);
D3D12_RESOURCE_BARRIER resourceBarrier;
resourceBarrier.Transition.pResource = renderTargetResources[renderTargetIndex].Get();
resourceBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
resourceBarrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
resourceBarrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
resourceBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
resourceBarrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
commandList->ResourceBarrier(1, &resourceBarrier);
ASSERT_SUCCESS(commandList->Close());
backend::d3d12::ExecuteCommandLists(backendDevice, { commandList.Get() });
}
nxtSwapChainError GetNextTexture(nxtSwapChainNextTexture* nextTexture) {
nextTexture->texture = renderTargetResources[renderTargetIndex].Get();
return NXT_SWAP_CHAIN_NO_ERROR;
}
nxtSwapChainError Present() {
// Current frame already transitioned to Present by the application, but
// we need to flush the D3D12 backend's pending transitions.
procs.deviceTick(backendDevice);
ASSERT_SUCCESS(swapChain->Present(1, 0));
// Transition last frame's render target back to being a render target
{
ComPtr<ID3D12GraphicsCommandList> commandList = {};
backend::d3d12::OpenCommandList(backendDevice, &commandList);
D3D12_RESOURCE_BARRIER resourceBarrier;
resourceBarrier.Transition.pResource = renderTargetResources[previousRenderTargetIndex].Get();
resourceBarrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
@@ -188,32 +206,47 @@ namespace utils {
lastSerialRenderTargetWasUsed[renderTargetIndex] = backend::d3d12::GetSerial(backendDevice);
// Tell the backend to render to the current render target
backend::d3d12::SetNextTexture(backendDevice, renderTargetResources[renderTargetIndex]);
return NXT_SWAP_CHAIN_NO_ERROR;
}
};
class D3D12Binding : public BackendBinding {
public:
void SetupGLFWWindowHints() override {
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
}
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
factory = CreateFactory();
ASSERT(GetHardwareAdapter(factory.Get(), &hardwareAdapter));
ASSERT_SUCCESS(D3D12CreateDevice(
hardwareAdapter.Get(),
D3D_FEATURE_LEVEL_11_0,
IID_PPV_ARGS(&d3d12Device)
));
backend::d3d12::Init(d3d12Device, procs, device);
backendDevice = *device;
procTable = *procs;
}
uint64_t GetSwapChainImplementation() override {
if (swapchainImpl.userData == nullptr) {
HWND win32Window = glfwGetWin32Window(window);
swapchainImpl = SwapChainImplD3D12::Create(win32Window, procTable);
}
return reinterpret_cast<uint64_t>(&swapchainImpl);
}
private:
nxtDevice backendDevice = nullptr;
static constexpr unsigned int kFrameCount = 2;
nxtSwapChainImplementation swapchainImpl = {};
nxtProcTable procTable = {};
// Initialization
ComPtr<IDXGIFactory4> factory;
ComPtr<IDXGIAdapter1> hardwareAdapter;
ComPtr<ID3D12Device> d3d12Device;
ComPtr<ID3D12CommandQueue> commandQueue;
ComPtr<IDXGISwapChain3> swapChain;
ComPtr<ID3D12Resource> renderTargetResources[kFrameCount];
// Frame synchronization. Updated every frame
uint32_t renderTargetIndex;
uint32_t previousRenderTargetIndex;
uint64_t lastSerialRenderTargetWasUsed[kFrameCount];
ComPtr<ID3D12GraphicsCommandList> commandList;
static void ASSERT_SUCCESS(HRESULT hr) {
ASSERT(SUCCEEDED(hr));
}
static bool GetHardwareAdapter(IDXGIFactory4* factory, IDXGIAdapter1** hardwareAdapter) {
*hardwareAdapter = nullptr;

View File

@@ -14,6 +14,10 @@
#include "utils/BackendBinding.h"
#include "common/Assert.h"
#include "nxt/nxt_wsi.h"
#include "utils/SwapChainImpl.h"
#define GLFW_EXPOSE_NATIVE_COCOA
#include "GLFW/glfw3.h"
#include "GLFW/glfw3native.h"
@@ -30,6 +34,103 @@ namespace metal {
}
namespace utils {
class SwapChainImplMTL : SwapChainImpl {
public:
static nxtSwapChainImplementation Create(id nswindow) {
auto impl = GenerateSwapChainImplementation<SwapChainImplMTL, nxtWSIContextMetal>();
impl.userData = new SwapChainImplMTL(nswindow);
return impl;
}
private:
id nsWindow = nil;
id<MTLDevice> mtlDevice = nil;
id<MTLCommandQueue> commandQueue = nil;
CAMetalLayer* layer = nullptr;
id<CAMetalDrawable> currentDrawable = nil;
id<MTLTexture> currentTexture = nil;
SwapChainImplMTL(id nsWindow)
: nsWindow(nsWindow) {
}
~SwapChainImplMTL() {
[currentTexture release];
[currentDrawable release];
}
// For GenerateSwapChainImplementation
friend class SwapChainImpl;
void Init(nxtWSIContextMetal* ctx) {
mtlDevice = ctx->device;
commandQueue = [mtlDevice newCommandQueue];
}
nxtSwapChainError Configure(nxtTextureFormat format,
uint32_t width, uint32_t height) {
if (format != NXT_TEXTURE_FORMAT_R8_G8_B8_A8_UNORM) {
return "unsupported format";
}
ASSERT(width > 0);
ASSERT(height > 0);
NSView* contentView = [nsWindow contentView];
[contentView setWantsLayer: YES];
CGSize size = {};
size.width = width;
size.height = height;
layer = [CAMetalLayer layer];
[layer setDevice: mtlDevice];
[layer setPixelFormat: MTLPixelFormatBGRA8Unorm];
[layer setFramebufferOnly: YES];
[layer setDrawableSize: size];
[contentView setLayer: layer];
return NXT_SWAP_CHAIN_NO_ERROR;
}
nxtSwapChainError GetNextTexture(nxtSwapChainNextTexture* nextTexture) {
[currentDrawable release];
currentDrawable = [layer nextDrawable];
[currentDrawable retain];
[currentTexture release];
currentTexture = currentDrawable.texture;
[currentTexture retain];
// Clear initial contents of the texture
{
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];
}
nextTexture->texture = reinterpret_cast<void*>(currentTexture);
return NXT_SWAP_CHAIN_NO_ERROR;
}
nxtSwapChainError Present() {
id<MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];
[commandBuffer presentDrawable: currentDrawable];
[commandBuffer commit];
return NXT_SWAP_CHAIN_NO_ERROR;
}
};
class MetalBinding : public BackendBinding {
public:
@@ -39,40 +140,21 @@ namespace utils {
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
metalDevice = MTLCreateSystemDefaultDevice();
id nsWindow = glfwGetCocoaWindow(window);
NSView* contentView = [nsWindow contentView];
[contentView setWantsLayer: YES];
layer = [CAMetalLayer layer];
[layer setDevice: metalDevice];
[layer setPixelFormat: MTLPixelFormatBGRA8Unorm];
[layer setFramebufferOnly: YES];
[layer setDrawableSize: [contentView bounds].size];
[contentView setLayer: layer];
backend::metal::Init(metalDevice, procs, device);
backendDevice = *device;
backend::metal::SetNextDrawable(backendDevice, GetNextDrawable());
}
void SwapBuffers() override {
backend::metal::Present(backendDevice);
backend::metal::SetNextDrawable(backendDevice, GetNextDrawable());
uint64_t GetSwapChainImplementation() override {
if (swapchainImpl.userData == nullptr) {
swapchainImpl = SwapChainImplMTL::Create(glfwGetCocoaWindow(window));
}
return reinterpret_cast<uint64_t>(&swapchainImpl);
}
private:
id<CAMetalDrawable> GetNextDrawable() {
lastDrawable = [layer nextDrawable];
return lastDrawable;
}
id<MTLDevice> metalDevice = nil;
CAMetalLayer* layer = nullptr;
id<CAMetalDrawable> lastDrawable = nil;
nxtDevice backendDevice = nullptr;
nxtSwapChainImplementation swapchainImpl = {};
};
BackendBinding* CreateMetalBinding() {

View File

@@ -92,34 +92,6 @@ namespace utils {
return builder.GetResult();
}
void CreateDefaultRenderPass(const nxt::Device& device, nxt::RenderPass* renderPass, nxt::Framebuffer* framebuffer) {
auto depthStencilTexture = device.CreateTextureBuilder()
.SetDimension(nxt::TextureDimension::e2D)
.SetExtent(640, 480, 1)
.SetFormat(nxt::TextureFormat::D32FloatS8Uint)
.SetMipLevels(1)
.SetAllowedUsage(nxt::TextureUsageBit::OutputAttachment)
.GetResult();
depthStencilTexture.FreezeUsage(nxt::TextureUsageBit::OutputAttachment);
auto depthStencilView = depthStencilTexture.CreateTextureViewBuilder()
.GetResult();
*renderPass = device.CreateRenderPassBuilder()
.SetAttachmentCount(2)
.AttachmentSetFormat(0, nxt::TextureFormat::R8G8B8A8Unorm)
.AttachmentSetFormat(1, nxt::TextureFormat::D32FloatS8Uint)
.SetSubpassCount(1)
.SubpassSetColorAttachment(0, 0, 0)
.SubpassSetDepthStencilAttachment(0, 1)
.GetResult();
*framebuffer = device.CreateFramebufferBuilder()
.SetRenderPass(*renderPass)
.SetDimensions(640, 480)
// Attachment 0 is implicit until we add WSI
.SetAttachment(1, depthStencilView)
.GetResult();
}
nxt::Buffer CreateFrozenBufferFromData(const nxt::Device& device, const void* data, uint32_t size, nxt::BufferUsageBit usage) {
nxt::Buffer buffer = device.CreateBufferBuilder()
.SetAllowedUsage(nxt::BufferUsageBit::TransferDst | usage)

View File

@@ -18,7 +18,6 @@ namespace utils {
void FillShaderModuleBuilder(const nxt::ShaderModuleBuilder& builder, nxt::ShaderStage stage, const char* source);
nxt::ShaderModule CreateShaderModule(const nxt::Device& device, nxt::ShaderStage stage, const char* source);
void CreateDefaultRenderPass(const nxt::Device& device, nxt::RenderPass* renderPass, nxt::Framebuffer* framebuffer);
nxt::Buffer CreateFrozenBufferFromData(const nxt::Device& device, const void* data, uint32_t size, nxt::BufferUsageBit usage);
}

View File

@@ -29,7 +29,8 @@ namespace utils {
void GetProcAndDevice(nxtProcTable* procs, nxtDevice* device) override {
backend::null::Init(procs, device);
}
void SwapBuffers() override {
uint64_t GetSwapChainImplementation() override {
return 0;
}
};

View File

@@ -14,20 +14,104 @@
#include "utils/BackendBinding.h"
#include "common/Assert.h"
#include "common/Platform.h"
#include "nxt/nxt_wsi.h"
#include "utils/SwapChainImpl.h"
#include <cstdio>
#include "glad/glad.h"
#include "GLFW/glfw3.h"
namespace backend {
namespace opengl {
void Init(void* (*getProc)(const char*), nxtProcTable* procs, nxtDevice* device);
void HACKCLEAR(nxtDevice device);
void InitBackbuffer(nxtDevice device);
void CommitBackbuffer(nxtDevice device);
}
}
namespace utils {
class SwapChainImplGL : SwapChainImpl {
public:
static nxtSwapChainImplementation Create(GLFWwindow* window) {
auto impl = GenerateSwapChainImplementation<SwapChainImplGL, nxtWSIContextGL>();
impl.userData = new SwapChainImplGL(window);
return impl;
}
private:
GLFWwindow* window = nullptr;
uint32_t cfgWidth = 0;
uint32_t cfgHeight = 0;
GLuint backFBO = 0;
GLuint backTexture = 0;
SwapChainImplGL(GLFWwindow* window)
: window(window) {
}
~SwapChainImplGL() {
glDeleteTextures(1, &backTexture);
glDeleteFramebuffers(1, &backFBO);
}
void HACKCLEAR() {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, backFBO);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
}
// For GenerateSwapChainImplementation
friend class SwapChainImpl;
void Init(nxtWSIContextGL*) {
glGenTextures(1, &backTexture);
glBindTexture(GL_TEXTURE_2D, backTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, 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);
}
nxtSwapChainError Configure(nxtTextureFormat format,
uint32_t width, uint32_t height) {
if (format != NXT_TEXTURE_FORMAT_R8_G8_B8_A8_UNORM) {
return "unsupported format";
}
ASSERT(width > 0);
ASSERT(height > 0);
cfgWidth = width;
cfgHeight = height;
glBindTexture(GL_TEXTURE_2D, backTexture);
// Reallocate the texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
// Clear the newly (re-)allocated texture
HACKCLEAR();
return NXT_SWAP_CHAIN_NO_ERROR;
}
nxtSwapChainError GetNextTexture(nxtSwapChainNextTexture* nextTexture) {
nextTexture->texture = reinterpret_cast<void*>(static_cast<size_t>(backTexture));
return NXT_SWAP_CHAIN_NO_ERROR;
}
nxtSwapChainError Present() {
glBindFramebuffer(GL_READ_FRAMEBUFFER, backFBO);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
glBlitFramebuffer(0, 0, cfgWidth, cfgHeight, 0, 0, cfgWidth, cfgHeight,
GL_COLOR_BUFFER_BIT, GL_NEAREST);
glfwSwapBuffers(window);
HACKCLEAR();
return NXT_SWAP_CHAIN_NO_ERROR;
}
};
class OpenGLBinding : public BackendBinding {
public:
void SetupGLFWWindowHints() override {
@@ -48,16 +132,18 @@ namespace utils {
backend::opengl::Init(reinterpret_cast<void*(*)(const char*)>(glfwGetProcAddress), procs, device);
backendDevice = *device;
backend::opengl::InitBackbuffer(backendDevice);
}
void SwapBuffers() override {
backend::opengl::CommitBackbuffer(backendDevice);
glfwSwapBuffers(window);
backend::opengl::HACKCLEAR(backendDevice);
uint64_t GetSwapChainImplementation() override {
if (swapchainImpl.userData == nullptr) {
swapchainImpl = SwapChainImplGL::Create(window);
}
return reinterpret_cast<uint64_t>(&swapchainImpl);
}
private:
nxtDevice backendDevice = nullptr;
nxtSwapChainImplementation swapchainImpl = {};
};
BackendBinding* CreateOpenGLBinding() {

47
src/utils/SwapChainImpl.h Normal file
View File

@@ -0,0 +1,47 @@
// Copyright 2017 The NXT Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef UTILS_SWAPCHAINIMPL_H_
#define UTILS_SWAPCHAINIMPL_H_
namespace utils {
class SwapChainImpl {
protected:
template<class TImpl, typename TWSIContext>
static nxtSwapChainImplementation GenerateSwapChainImplementation() {
nxtSwapChainImplementation impl = {};
impl.Init = [](void* userData, void* wsiContext) {
auto* ctx = reinterpret_cast<TWSIContext*>(wsiContext);
reinterpret_cast<TImpl*>(userData)->Init(ctx);
};
impl.Destroy = [](void* userData) {
delete reinterpret_cast<TImpl*>(userData);
};
impl.Configure = [](void* userData, nxtTextureFormat format, uint32_t width, uint32_t height) {
return reinterpret_cast<TImpl*>(userData)->Configure(
format, width, height);
};
impl.GetNextTexture = [](void* userData, nxtSwapChainNextTexture* nextTexture) {
return reinterpret_cast<TImpl*>(userData)->GetNextTexture(
nextTexture);
};
impl.Present = [](void* userData) {
return reinterpret_cast<TImpl*>(userData)->Present();
};
return impl;
}
};
}
#endif // UTILS_SWAPCHAINIMPL_H_