Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/cube/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ namespace plume {
ctx.m_device = renderInterface->createDevice();
ctx.m_commandQueue = ctx.m_device->createCommandQueue(RenderCommandListType::DIRECT);
ctx.m_fence = ctx.m_device->createCommandFence();
ctx.m_swapChain = ctx.m_commandQueue->createSwapChain(ctx.m_renderWindow, BufferCount, SwapchainFormat, 2);
ctx.m_swapChain = ctx.m_commandQueue->createSwapChain(RenderSwapChainDesc(ctx.m_renderWindow, SwapchainFormat, BufferCount));
ctx.m_swapChain->resize();
ctx.m_commandList = ctx.m_commandQueue->createCommandList();
ctx.m_acquireSemaphore = ctx.m_device->createCommandSemaphore();
Expand Down
2 changes: 1 addition & 1 deletion examples/triangle/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ namespace plume {
ctx.m_fence = ctx.m_device->createCommandFence();

// Create a swap chain for the window using the render window from init
ctx.m_swapChain = ctx.m_commandQueue->createSwapChain(ctx.m_renderWindow, BufferCount, SwapchainFormat, 2);
ctx.m_swapChain = ctx.m_commandQueue->createSwapChain(RenderSwapChainDesc(ctx.m_renderWindow, SwapchainFormat, BufferCount));

// Explicitly resize the swapchain to create the textures
ctx.m_swapChain->resize();
Expand Down
50 changes: 25 additions & 25 deletions plume_d3d12.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1315,18 +1315,15 @@ namespace plume {

// D3D12SwapChain

D3D12SwapChain::D3D12SwapChain(D3D12CommandQueue *commandQueue, RenderWindow renderWindow, uint32_t textureCount, RenderFormat format, uint32_t maxFrameLatency) {
D3D12SwapChain::D3D12SwapChain(D3D12CommandQueue *commandQueue, const RenderSwapChainDesc &desc) {
assert(commandQueue != nullptr);
assert(renderWindow != 0);
assert(desc.renderWindow != 0);

this->commandQueue = commandQueue;
this->renderWindow = renderWindow;
this->textureCount = textureCount;
this->format = format;
this->maxFrameLatency = maxFrameLatency;
this->desc = desc;

// Store the native format representation.
nativeFormat = toDXGI(format);
nativeFormat = toDXGI(desc.format);

getWindowSize(width, height);

Expand All @@ -1336,7 +1333,7 @@ namespace plume {
}

DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
swapChainDesc.BufferCount = textureCount;
swapChainDesc.BufferCount = desc.textureCount;
swapChainDesc.Width = width;
swapChainDesc.Height = height;
swapChainDesc.Format = nativeFormat;
Expand All @@ -1347,28 +1344,28 @@ namespace plume {

IDXGISwapChain1 *swapChain1;
IDXGIFactory4 *dxgiFactory = commandQueue->device->renderInterface->dxgiFactory;
HRESULT res = dxgiFactory->CreateSwapChainForHwnd(commandQueue->d3d, renderWindow, &swapChainDesc, nullptr, nullptr, &swapChain1);
HRESULT res = dxgiFactory->CreateSwapChainForHwnd(commandQueue->d3d, desc.renderWindow, &swapChainDesc, nullptr, nullptr, &swapChain1);
if (FAILED(res)) {
fprintf(stderr, "CreateSwapChainForHwnd failed with error code 0x%lX.\n", res);
return;
}

res = dxgiFactory->MakeWindowAssociation(renderWindow, DXGI_MWA_NO_ALT_ENTER);
res = dxgiFactory->MakeWindowAssociation(desc.renderWindow, DXGI_MWA_NO_ALT_ENTER);
if (FAILED(res)) {
fprintf(stderr, "MakeWindowAssociation failed with error code 0x%lX.\n", res);
return;
}

d3d = static_cast<IDXGISwapChain3 *>(swapChain1);
d3d->SetMaximumFrameLatency(maxFrameLatency);
d3d->SetMaximumFrameLatency(desc.maxFrameLatency);
waitableObject = d3d->GetFrameLatencyWaitableObject();

textures.resize(textureCount);
textures.resize(desc.textureCount);

for (uint32_t i = 0; i < textureCount; i++) {
for (uint32_t i = 0; i < desc.textureCount; i++) {
textures[i].device = commandQueue->device;
textures[i].desc.dimension = RenderTextureDimension::TEXTURE_2D;
textures[i].desc.format = format;
textures[i].desc.format = desc.format;
textures[i].desc.depth = 1;
textures[i].desc.mipLevels = 1;
textures[i].desc.arraySize = 1;
Expand All @@ -1379,7 +1376,7 @@ namespace plume {
}

D3D12SwapChain::~D3D12SwapChain() {
for (uint32_t i = 0; i < textureCount; i++) {
for (uint32_t i = 0; i < desc.textureCount; i++) {
if (textures[i].d3d != nullptr) {
textures[i].d3d->Release();
textures[i].d3d = nullptr;
Expand All @@ -1392,14 +1389,17 @@ namespace plume {
}

bool D3D12SwapChain::present(uint32_t textureIndex, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount) {
// If using present wait, we prefer using a SyncInterval of 0 even when Vsync is enabled. Tearing won't happen if DXGI_PRESENT_ALLOW_TEARING is not specified.
const bool tearingAllowed = (swapChainFlags & DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING) != 0U;
UINT syncInterval = vsyncEnabled ? 1 : 0;
UINT flags = (tearingAllowed && !vsyncEnabled) ? DXGI_PRESENT_ALLOW_TEARING : 0;
UINT syncInterval = (vsyncEnabled && !desc.enablePresentWait) ? 1 : 0;
UINT flags = (!vsyncEnabled && tearingAllowed) ? DXGI_PRESENT_ALLOW_TEARING : 0;
HRESULT res = d3d->Present(syncInterval, flags);
return SUCCEEDED(res);
}

void D3D12SwapChain::wait() {
assert(desc.enablePresentWait && "Present wait should've been explicitly enabled during swap chain creation before using the wait function.");

if (waitableObject != NULL) {
WaitForSingleObject(waitableObject, INFINITE);
}
Expand All @@ -1413,7 +1413,7 @@ namespace plume {
return false;
}

for (uint32_t i = 0; i < textureCount; i++) {
for (uint32_t i = 0; i < desc.textureCount; i++) {
textures[i].d3d->Release();
textures[i].d3d = nullptr;
}
Expand Down Expand Up @@ -1452,15 +1452,15 @@ namespace plume {

void D3D12SwapChain::getWindowSize(uint32_t &dstWidth, uint32_t &dstHeight) const {
RECT rect;
GetClientRect(renderWindow, &rect);
GetClientRect(desc.renderWindow, &rect);
dstWidth = rect.right - rect.left;
dstHeight = rect.bottom - rect.top;
}

void D3D12SwapChain::setTextures() {
assert(textureCount == textures.size());
assert(desc.textureCount == textures.size());

for (uint32_t i = 0; i < textureCount; i++) {
for (uint32_t i = 0; i < desc.textureCount; i++) {
d3d->GetBuffer(i, IID_PPV_ARGS(&textures[i].d3d));

textures[i].desc.width = width;
Expand All @@ -1475,7 +1475,7 @@ namespace plume {
}

uint32_t D3D12SwapChain::getTextureCount() const {
return textureCount;
return desc.textureCount;
}

bool D3D12SwapChain::acquireTexture(RenderCommandSemaphore *signalSemaphore, uint32_t *textureIndex) {
Expand All @@ -1485,7 +1485,7 @@ namespace plume {
}

RenderWindow D3D12SwapChain::getWindow() const {
return renderWindow;
return desc.renderWindow;
}

bool D3D12SwapChain::isEmpty() const {
Expand Down Expand Up @@ -2672,8 +2672,8 @@ namespace plume {
return std::make_unique<D3D12CommandList>(this);
}

std::unique_ptr<RenderSwapChain> D3D12CommandQueue::createSwapChain(RenderWindow renderWindow, uint32_t bufferCount, RenderFormat format, uint32_t maxFrameLatency) {
return std::make_unique<D3D12SwapChain>(this, renderWindow, bufferCount, format, maxFrameLatency);
std::unique_ptr<RenderSwapChain> D3D12CommandQueue::createSwapChain(const RenderSwapChainDesc &desc) {
return std::make_unique<D3D12SwapChain>(this, desc);
}

void D3D12CommandQueue::executeCommandLists(const RenderCommandList **commandLists, uint32_t commandListCount, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount, RenderCommandSemaphore **signalSemaphores, uint32_t signalSemaphoreCount, RenderCommandFence *signalFence) {
Expand Down
9 changes: 3 additions & 6 deletions plume_d3d12.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,22 +100,19 @@ namespace plume {
};

struct D3D12SwapChain : RenderSwapChain {
RenderSwapChainDesc desc;
IDXGISwapChain3 *d3d = nullptr;
HANDLE waitableObject = 0;
D3D12CommandQueue *commandQueue = nullptr;
RenderWindow renderWindow = {};
std::vector<D3D12Texture> textures;
uint32_t textureCount = 0;
RenderFormat format = RenderFormat::UNKNOWN;
DXGI_FORMAT nativeFormat = DXGI_FORMAT_UNKNOWN;
uint32_t width = 0;
uint32_t height = 0;
uint32_t refreshRate = 0;
bool vsyncEnabled = true;
uint32_t maxFrameLatency = 0;
UINT swapChainFlags = 0;

D3D12SwapChain(D3D12CommandQueue *commandQueue, RenderWindow renderWindow, uint32_t textureCount, RenderFormat format, uint32_t maxFrameLatency);
D3D12SwapChain(D3D12CommandQueue *commandQueue, const RenderSwapChainDesc &desc);
~D3D12SwapChain() override;
bool present(uint32_t textureIndex, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount) override;
void wait() override;
Expand Down Expand Up @@ -266,7 +263,7 @@ namespace plume {
D3D12CommandQueue(D3D12Device *device, RenderCommandListType type);
~D3D12CommandQueue() override;
std::unique_ptr<RenderCommandList> createCommandList() override;
std::unique_ptr<RenderSwapChain> createSwapChain(RenderWindow renderWindow, uint32_t textureCount, RenderFormat format, uint32_t newFrameLatency) override;
std::unique_ptr<RenderSwapChain> createSwapChain(const RenderSwapChainDesc &desc) override;
void executeCommandLists(const RenderCommandList **commandLists, uint32_t commandListCount, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount, RenderCommandSemaphore **signalSemaphores, uint32_t signalSemaphoreCount, RenderCommandFence *signalFence) override;
void waitForCommandFence(RenderCommandFence *fence) override;
};
Expand Down
25 changes: 13 additions & 12 deletions plume_metal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1900,19 +1900,18 @@ namespace plume {

// MetalSwapChain

MetalSwapChain::MetalSwapChain(MetalCommandQueue *commandQueue, const RenderWindow renderWindow, uint32_t textureCount, const RenderFormat format, uint32_t maxFrameLatency) {
this->layer = static_cast<CA::MetalLayer*>(renderWindow.view);
MetalSwapChain::MetalSwapChain(MetalCommandQueue *commandQueue, const RenderSwapChainDesc &desc) {
this->layer = static_cast<CA::MetalLayer*>(desc.renderWindow.view);
layer->setDevice(commandQueue->device->mtl);
layer->setPixelFormat(mapPixelFormat(format));
layer->setPixelFormat(mapPixelFormat(desc.format));

this->commandQueue = commandQueue;
this->maxFrameLatency = maxFrameLatency;
this->desc = desc;

// Metal supports a maximum of 3 drawables.
this->drawables.resize(MAX_DRAWABLES);

this->renderWindow = renderWindow;
this->windowWrapper = std::make_unique<CocoaWindow>(renderWindow.window);
this->windowWrapper = std::make_unique<CocoaWindow>(desc.renderWindow.window);
getWindowSize(width, height);

// Set the layer's drawable size to match the window size
Expand All @@ -1925,7 +1924,7 @@ namespace plume {
MetalDrawable &drawable = this->drawables[i];
drawable.desc.width = width;
drawable.desc.height = height;
drawable.desc.format = format;
drawable.desc.format = desc.format;
drawable.desc.flags = RenderTextureFlag::RENDER_TARGET;
}
}
Expand Down Expand Up @@ -1978,10 +1977,12 @@ namespace plume {
}

void MetalSwapChain::wait() {
if (currentPresentId >= maxFrameLatency) {
assert(desc.enablePresentWait && "Present wait should've been explicitly enabled during swap chain creation before using the wait function.");

if (currentPresentId >= desc.maxFrameLatency) {
std::unique_lock lock(lastPresentedIdMutex);
lastPresentedIdCondVar.wait_for(lock, std::chrono::seconds(1), [this] {
return lastPresentedId >= currentPresentId - (maxFrameLatency - 1);
return lastPresentedId >= currentPresentId - (desc.maxFrameLatency - 1);
});
}
}
Expand Down Expand Up @@ -2079,7 +2080,7 @@ namespace plume {
}

RenderWindow MetalSwapChain::getWindow() const {
return renderWindow;
return desc.renderWindow;
}

bool MetalSwapChain::isEmpty() const {
Expand Down Expand Up @@ -3676,8 +3677,8 @@ namespace plume {
return std::make_unique<MetalCommandList>(this);
}

std::unique_ptr<RenderSwapChain> MetalCommandQueue::createSwapChain(RenderWindow renderWindow, uint32_t textureCount, RenderFormat format, uint32_t maxFrameLatency) {
return std::make_unique<MetalSwapChain>(this, renderWindow, textureCount, format, maxFrameLatency);
std::unique_ptr<RenderSwapChain> MetalCommandQueue::createSwapChain(const RenderSwapChainDesc &desc) {
return std::make_unique<MetalSwapChain>(this, desc);
}

void MetalCommandQueue::executeCommandLists(const RenderCommandList **commandLists, const uint32_t commandListCount, RenderCommandSemaphore **waitSemaphores, const uint32_t waitSemaphoreCount, RenderCommandSemaphore **signalSemaphores, const uint32_t signalSemaphoreCount, RenderCommandFence *signalFence) {
Expand Down
8 changes: 3 additions & 5 deletions plume_metal.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,25 +234,23 @@ namespace plume {
};

struct MetalSwapChain : RenderSwapChain {
RenderSwapChainDesc desc;
CA::MetalLayer *layer = nullptr;
MetalCommandQueue *commandQueue = nullptr;
RenderFormat format = RenderFormat::UNKNOWN;
uint32_t width = 0;
uint32_t height = 0;
uint32_t refreshRate = 0;
std::vector<MetalDrawable> drawables;
uint32_t currentAvailableDrawableIndex = 0;
RenderWindow renderWindow = {};
std::unique_ptr<CocoaWindow> windowWrapper;

// Present wait
uint32_t maxFrameLatency = 0;
uint64_t currentPresentId = 0;
uint64_t lastPresentedId = 0;
std::mutex lastPresentedIdMutex;
std::condition_variable lastPresentedIdCondVar;

MetalSwapChain(MetalCommandQueue *commandQueue, RenderWindow renderWindow, uint32_t textureCount, RenderFormat format, uint32_t maxFrameLatency);
MetalSwapChain(MetalCommandQueue *commandQueue, const RenderSwapChainDesc &desc);
~MetalSwapChain() override;
bool present(uint32_t textureIndex, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount) override;
void wait() override;
Expand Down Expand Up @@ -550,7 +548,7 @@ namespace plume {
MetalCommandQueue(MetalDevice *device, RenderCommandListType type);
~MetalCommandQueue() override;
std::unique_ptr<RenderCommandList> createCommandList() override;
std::unique_ptr<RenderSwapChain> createSwapChain(RenderWindow renderWindow, uint32_t bufferCount, RenderFormat format, uint32_t maxFrameLatency) override;
std::unique_ptr<RenderSwapChain> createSwapChain(const RenderSwapChainDesc &desc) override;
void executeCommandLists(const RenderCommandList **commandLists, uint32_t commandListCount, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount, RenderCommandSemaphore **signalSemaphores, uint32_t signalSemaphoreCount, RenderCommandFence *signalFence) override;
void waitForCommandFence(RenderCommandFence *fence) override;
};
Expand Down
2 changes: 1 addition & 1 deletion plume_render_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ namespace plume {
struct RenderCommandQueue {
virtual ~RenderCommandQueue() { }
virtual std::unique_ptr<RenderCommandList> createCommandList() = 0;
virtual std::unique_ptr<RenderSwapChain> createSwapChain(RenderWindow renderWindow, uint32_t textureCount, RenderFormat format, uint32_t maxFrameLatency) = 0;
virtual std::unique_ptr<RenderSwapChain> createSwapChain(const RenderSwapChainDesc &desc) = 0;
virtual void executeCommandLists(const RenderCommandList **commandLists, uint32_t commandListCount, RenderCommandSemaphore **waitSemaphores = nullptr, uint32_t waitSemaphoreCount = 0, RenderCommandSemaphore **signalSemaphores = nullptr, uint32_t signalSemaphoreCount = 0, RenderCommandFence *signalFence = nullptr) = 0;
virtual void waitForCommandFence(RenderCommandFence *fence) = 0;

Expand Down
20 changes: 20 additions & 0 deletions plume_render_interface_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -1139,6 +1139,26 @@ namespace plume {
bool allowOnlyBuffers = false;
};

struct RenderSwapChainDesc {
RenderWindow renderWindow = {};
RenderFormat format = RenderFormat::UNKNOWN;
uint32_t textureCount = 0;

// The capability for presentWait must be supported by the RenderDevice.
bool enablePresentWait = false;
uint32_t maxFrameLatency = 0;

RenderSwapChainDesc() = default;

RenderSwapChainDesc(RenderWindow renderWindow, RenderFormat format, uint32_t textureCount, bool enablePresentWait = false, uint32_t maxFrameLatency = 0) {
this->renderWindow = renderWindow;
this->format = format;
this->textureCount = textureCount;
this->enablePresentWait = enablePresentWait;
this->maxFrameLatency = maxFrameLatency;
}
};

struct RenderInputSlot {
uint32_t index = 0;
uint32_t stride = 0;
Expand Down
Loading
Loading