mirror of
https://github.com/SysRay/psOff_public.git
synced 2024-11-27 00:20:54 +00:00
videoout| handle swapchain with imageHandler
This commit is contained in:
parent
8e459d7576
commit
ed0112d595
@ -117,6 +117,12 @@ class IGraphics {
|
||||
*/
|
||||
virtual void deinit() = 0;
|
||||
|
||||
/**
|
||||
* @brief Call before deinit, stops all incoming requests
|
||||
*
|
||||
*/
|
||||
virtual void stop() = 0;
|
||||
|
||||
/**
|
||||
* @brief Register a display buffer
|
||||
*
|
||||
|
@ -2,9 +2,10 @@ add_library(videoout OBJECT
|
||||
videoout.cpp
|
||||
vulkan/vulkanSetup.cpp
|
||||
vulkan/vulkanHelper.cpp
|
||||
imageHandler.cpp
|
||||
)
|
||||
|
||||
add_dependencies(videoout third_party psOff_utility initParams imports)
|
||||
add_dependencies(videoout third_party psOff_utility initParams imports boost)
|
||||
target_include_directories(videoout PRIVATE
|
||||
${Vulkan_INCLUDE_DIRS}
|
||||
${PRJ_SRC_DIR}/third_party/optick/src
|
||||
|
238
core/videoout/imageHandler.cpp
Normal file
238
core/videoout/imageHandler.cpp
Normal file
@ -0,0 +1,238 @@
|
||||
#include "imageHandler.h"
|
||||
|
||||
#include "logging.h"
|
||||
#include "vulkan/vulkanSetup.h"
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <vulkan/vk_enum_string_helper.h>
|
||||
|
||||
LOG_DEFINE_MODULE(ImageHandler);
|
||||
|
||||
constexpr uint32_t NUM_DISPLAY_BUFFERS = 3;
|
||||
|
||||
class ImageHandler: public IImageHandler {
|
||||
uint32_t m_maxImages = 1;
|
||||
|
||||
VkDevice m_device;
|
||||
|
||||
// Vulkan internal
|
||||
VkSwapchainKHR m_swapchain = nullptr;
|
||||
VkCommandPool m_commandPool = nullptr;
|
||||
|
||||
std::vector<VkSemaphore> m_semsImageReady;
|
||||
std::vector<VkSemaphore> m_semsImageCopied;
|
||||
std::vector<VkCommandBuffer> m_commandBuffer;
|
||||
|
||||
size_t m_nextIndex = 0;
|
||||
|
||||
std::vector<VkImage> m_scImages;
|
||||
// - vulkan
|
||||
|
||||
boost::mutex m_mutexInt;
|
||||
|
||||
size_t m_waitId = 0;
|
||||
size_t m_presentCount = 1;
|
||||
|
||||
boost::condition_variable m_present_condVar; /// regulates number of images
|
||||
|
||||
bool m_stop = false;
|
||||
|
||||
public:
|
||||
ImageHandler(VkDevice vkDevice, VkExtent2D extentWindow, vulkan::QueueInfo* queue): IImageHandler(extentWindow, queue), m_device(vkDevice) {};
|
||||
|
||||
virtual ~ImageHandler() = default;
|
||||
|
||||
// ### Interace
|
||||
void init(vulkan::VulkanObj* obj, VkSurfaceKHR surface) final;
|
||||
void deinit() final;
|
||||
|
||||
void stop() final {
|
||||
m_stop = true;
|
||||
m_present_condVar.notify_all();
|
||||
}
|
||||
|
||||
std::optional<ImageData> getImage_blocking() final;
|
||||
|
||||
void notify_done(ImageData const&) final;
|
||||
|
||||
VkSwapchainKHR getSwapchain() const final { return m_swapchain; }
|
||||
};
|
||||
|
||||
std::unique_ptr<IImageHandler> createImageHandler(VkDevice vkDevice, VkExtent2D extentWindow, vulkan::QueueInfo* queue) {
|
||||
return std::make_unique<ImageHandler>(vkDevice, extentWindow, queue);
|
||||
}
|
||||
|
||||
std::optional<ImageData> ImageHandler::getImage_blocking() {
|
||||
LOG_USE_MODULE(ImageHandler);
|
||||
|
||||
boost::unique_lock lock(m_mutexInt);
|
||||
|
||||
// Regulate max images
|
||||
auto waitId = ++m_waitId;
|
||||
LOG_DEBUG(L"waitId:%llu presentCount:%llu", waitId, m_presentCount);
|
||||
m_present_condVar.wait(lock, [this, &waitId] { return m_stop || waitId == m_presentCount; });
|
||||
if (m_stop) return {};
|
||||
// -
|
||||
|
||||
ImageData imageData;
|
||||
imageData.semImageReady = m_semsImageReady[m_nextIndex];
|
||||
imageData.semImageCopied = m_semsImageCopied[m_nextIndex];
|
||||
imageData.cmdBuffer = m_commandBuffer[m_nextIndex];
|
||||
|
||||
// Get swapchain image
|
||||
{
|
||||
int numTries = 2;
|
||||
|
||||
VkResult result = VK_SUCCESS;
|
||||
for (; numTries >= 0; --numTries) {
|
||||
if (result = vkAcquireNextImageKHR(m_device, m_swapchain, UINT64_MAX, imageData.semImageReady, VK_NULL_HANDLE, &imageData.index); result != VK_SUCCESS) {
|
||||
if (result == VK_NOT_READY) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
}
|
||||
} else
|
||||
break;
|
||||
}
|
||||
if (numTries <= 0) {
|
||||
LOG_ERR(L"vkAcquireNextImageKHR %S", string_VkResult(result));
|
||||
++m_presentCount; // fake present
|
||||
lock.unlock();
|
||||
m_present_condVar.notify_all();
|
||||
return {};
|
||||
}
|
||||
}
|
||||
// - swapchain image
|
||||
|
||||
m_nextIndex = (++m_nextIndex) % m_maxImages;
|
||||
|
||||
imageData.swapchainImage = m_scImages[imageData.index];
|
||||
|
||||
imageData.extent = m_extentWindow;
|
||||
|
||||
{ // Begin commandbuffer| end is done by user
|
||||
VkCommandBufferBeginInfo const beginInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
||||
.flags = 0,
|
||||
.pInheritanceInfo = nullptr,
|
||||
};
|
||||
|
||||
if (auto result = vkBeginCommandBuffer(imageData.cmdBuffer, &beginInfo); result != VK_SUCCESS) {
|
||||
LOG_CRIT(L"Error vkBeginCommandBuffer: %S", string_VkResult(result));
|
||||
}
|
||||
}
|
||||
|
||||
return imageData;
|
||||
}
|
||||
|
||||
void ImageHandler::notify_done(ImageData const& imageData) {
|
||||
LOG_USE_MODULE(ImageHandler);
|
||||
boost::unique_lock lock(m_mutexInt);
|
||||
|
||||
vkResetCommandBuffer(imageData.cmdBuffer, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
|
||||
|
||||
++m_presentCount;
|
||||
lock.unlock();
|
||||
|
||||
m_present_condVar.notify_all();
|
||||
}
|
||||
|
||||
void ImageHandler::init(vulkan::VulkanObj* obj, VkSurfaceKHR surface) {
|
||||
LOG_USE_MODULE(ImageHandler);
|
||||
|
||||
{ // Create Display ready sems
|
||||
VkSemaphoreCreateInfo const semCreateInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
||||
.pNext = 0,
|
||||
.flags = 0,
|
||||
};
|
||||
m_semsImageReady.resize(m_maxImages);
|
||||
m_semsImageCopied.resize(m_maxImages);
|
||||
|
||||
for (size_t n = 0; n < m_maxImages; ++n) {
|
||||
vkCreateSemaphore(m_device, &semCreateInfo, nullptr, &m_semsImageReady[n]);
|
||||
vkCreateSemaphore(m_device, &semCreateInfo, nullptr, &m_semsImageCopied[n]);
|
||||
}
|
||||
}
|
||||
|
||||
auto numBuffers = NUM_DISPLAY_BUFFERS;
|
||||
|
||||
{ // swapchain
|
||||
numBuffers = std::clamp(numBuffers, obj->surfaceCapabilities.capabilities.minImageCount, obj->surfaceCapabilities.capabilities.maxImageCount);
|
||||
|
||||
m_extentWindow.width = std::clamp(m_extentWindow.width, obj->surfaceCapabilities.capabilities.minImageExtent.width,
|
||||
obj->surfaceCapabilities.capabilities.maxImageExtent.width);
|
||||
m_extentWindow.height = std::clamp(m_extentWindow.height, obj->surfaceCapabilities.capabilities.minImageExtent.height,
|
||||
obj->surfaceCapabilities.capabilities.maxImageExtent.height);
|
||||
|
||||
auto [displayFormat, displayColorSpace] = getDisplayFormat(obj);
|
||||
m_imageFormat = displayFormat;
|
||||
|
||||
VkSwapchainCreateInfoKHR const createInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
.surface = surface,
|
||||
.minImageCount = numBuffers,
|
||||
.imageFormat = m_imageFormat,
|
||||
.imageColorSpace = displayColorSpace,
|
||||
.imageExtent = m_extentWindow,
|
||||
.imageArrayLayers = 1,
|
||||
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
||||
.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.queueFamilyIndexCount = 0,
|
||||
.pQueueFamilyIndices = nullptr,
|
||||
.preTransform = obj->surfaceCapabilities.capabilities.currentTransform,
|
||||
.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
|
||||
.presentMode = VK_PRESENT_MODE_FIFO_KHR, // todo config vsync
|
||||
.clipped = VK_TRUE,
|
||||
.oldSwapchain = nullptr,
|
||||
};
|
||||
|
||||
vkCreateSwapchainKHR(obj->deviceInfo.device, &createInfo, nullptr, &m_swapchain);
|
||||
}
|
||||
|
||||
{ // swapchain images
|
||||
uint32_t numImages = 0;
|
||||
vkGetSwapchainImagesKHR(m_device, m_swapchain, &numImages, nullptr);
|
||||
m_scImages.resize(numImages);
|
||||
|
||||
vkGetSwapchainImagesKHR(m_device, m_swapchain, &numImages, m_scImages.data());
|
||||
}
|
||||
|
||||
{ // Command buffer
|
||||
|
||||
VkCommandPoolCreateInfo const poolInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||
.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
|
||||
.queueFamilyIndex = m_queue->family,
|
||||
};
|
||||
|
||||
if (auto result = vkCreateCommandPool(obj->deviceInfo.device, &poolInfo, nullptr, &m_commandPool); result != VK_SUCCESS) {
|
||||
LOG_CRIT(L"Couldn't create commandpool(graphics): %d", result);
|
||||
}
|
||||
|
||||
m_commandBuffer.resize(m_maxImages);
|
||||
VkCommandBufferAllocateInfo const allocInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
.commandPool = m_commandPool,
|
||||
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||
.commandBufferCount = m_maxImages,
|
||||
};
|
||||
|
||||
if (auto result = vkAllocateCommandBuffers(obj->deviceInfo.device, &allocInfo, m_commandBuffer.data()); result != VK_SUCCESS) {
|
||||
LOG_CRIT(L"Couldn't create commandbuffers(graphics): %d", result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImageHandler::deinit() {
|
||||
printf("deinit ImageHandler\n");
|
||||
|
||||
for (auto& sem: m_semsImageReady) {
|
||||
vkDestroySemaphore(m_device, sem, nullptr);
|
||||
}
|
||||
|
||||
if (m_commandPool != nullptr) vkDestroyCommandPool(m_device, m_commandPool, nullptr);
|
||||
if (m_swapchain != nullptr) vkDestroySwapchainKHR(m_device, m_swapchain, nullptr);
|
||||
|
||||
printf("deinit ImageHandler| done\n");
|
||||
}
|
54
core/videoout/imageHandler.h
Normal file
54
core/videoout/imageHandler.h
Normal file
@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
#include "utility/utility.h"
|
||||
|
||||
#include <optional>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
struct ImageData {
|
||||
VkImage swapchainImage = nullptr;
|
||||
VkSemaphore semImageReady = nullptr; /// image is ready for operation
|
||||
VkSemaphore semImageCopied = nullptr; /// Image has been copied, ready to swap
|
||||
VkCommandBuffer cmdBuffer = nullptr; /// Commandbuffer to be used for transer etc. Already called begin!
|
||||
|
||||
VkExtent2D extent;
|
||||
uint32_t index = 0;
|
||||
};
|
||||
|
||||
namespace vulkan {
|
||||
struct VulkanObj;
|
||||
struct QueueInfo;
|
||||
} // namespace vulkan
|
||||
|
||||
class IImageHandler {
|
||||
CLASS_NO_COPY(IImageHandler);
|
||||
CLASS_NO_MOVE(IImageHandler);
|
||||
|
||||
protected:
|
||||
IImageHandler(VkExtent2D extentWindow, vulkan::QueueInfo* queue): m_extentWindow(extentWindow), m_queue(queue) {}
|
||||
|
||||
VkExtent2D m_extentWindow;
|
||||
VkFormat m_imageFormat;
|
||||
|
||||
vulkan::QueueInfo* m_queue;
|
||||
|
||||
public:
|
||||
virtual ~IImageHandler() = default;
|
||||
|
||||
auto getExtent() const { return m_extentWindow; }
|
||||
|
||||
auto getFormat() const { return m_imageFormat; }
|
||||
|
||||
auto getQueue() const { return m_queue; }
|
||||
|
||||
virtual void init(vulkan::VulkanObj* obj, VkSurfaceKHR surface) = 0;
|
||||
|
||||
virtual void deinit() = 0;
|
||||
virtual void stop() = 0;
|
||||
|
||||
virtual std::optional<ImageData> getImage_blocking() = 0;
|
||||
virtual void notify_done(ImageData const&) = 0;
|
||||
|
||||
virtual VkSwapchainKHR getSwapchain() const = 0;
|
||||
};
|
||||
|
||||
std::unique_ptr<IImageHandler> createImageHandler(VkDevice vkDevice, VkExtent2D extentWindow, vulkan::QueueInfo* queue);
|
@ -8,3 +8,16 @@
|
||||
|
||||
![](../../out/docs/uml/modules/videoout_class.svg)
|
||||
</div>
|
||||
|
||||
### Swapchain image handling
|
||||
|
||||
User calls getImage_blocking() to retrieve the display image. After present notify_done() is called.
|
||||
|
||||
getImage_blocking() releases users FIFO. The whole swapchain images are handled by ImageHandler
|
||||
|
||||
|
||||
<div align="center">
|
||||
|
||||
![](../../out/docs/uml/modules/videout_swapchain.svg)
|
||||
|
||||
</div>
|
@ -10,6 +10,7 @@
|
||||
#include "core/kernel/eventqueue.h"
|
||||
#include "core/systemContent/systemContent.h"
|
||||
#include "core/timer/timer.h"
|
||||
#include "imageHandler.h"
|
||||
#include "logging.h"
|
||||
#include "modules/libSceVideoOut/codes.h"
|
||||
#include "modules/libSceVideoOut/types.h"
|
||||
@ -129,7 +130,7 @@ struct Message {
|
||||
int index = 0;
|
||||
uint32_t setIndex = 0;
|
||||
|
||||
vulkan::PresentData presentData = {};
|
||||
ImageData imageData = {};
|
||||
};
|
||||
|
||||
std::string getTitle(int handle, uint64_t frame, size_t fps, FlipRate maxFPS) {
|
||||
@ -152,12 +153,14 @@ class VideoOut: public IVideoOut, private IEventsGraphics {
|
||||
mutable std::mutex m_mutexInt;
|
||||
vulkan::VulkanObj* m_vulkanObj = nullptr;
|
||||
|
||||
std::unique_ptr<IGraphics> m_graphics;
|
||||
std::thread m_threadSDL2;
|
||||
std::condition_variable m_condSDL2;
|
||||
std::condition_variable m_condDone;
|
||||
bool m_stop = false;
|
||||
std::queue<Message> m_messages;
|
||||
std::unique_ptr<IGraphics> m_graphics;
|
||||
std::unique_ptr<IImageHandler> m_imageHandler;
|
||||
|
||||
std::thread m_threadSDL2;
|
||||
std::condition_variable m_condSDL2;
|
||||
std::condition_variable m_condDone;
|
||||
bool m_stop = false;
|
||||
std::queue<Message> m_messages;
|
||||
|
||||
uint64_t m_vblankTime = (uint64_t)(1e6 / 59.0); // in us
|
||||
|
||||
@ -178,15 +181,7 @@ class VideoOut: public IVideoOut, private IEventsGraphics {
|
||||
auto& swapchain = window.config.bufferSets[setIndex];
|
||||
auto& displayBufferMeta = swapchain.buffers[index];
|
||||
|
||||
LOG_DEBUG(L"-> eventDoFlip(%d):%u %d", handle, setIndex, index);
|
||||
auto const presentData = transferDisplay(swapchain, displayBufferMeta, waitSema, waitValue);
|
||||
|
||||
if (presentData.displayReady == nullptr) {
|
||||
LOG_ERR(L"<- submitFlip(%d):%u %d error", handle, setIndex, index);
|
||||
m_graphics->submitDone();
|
||||
doFlip(window, handle);
|
||||
return;
|
||||
}
|
||||
auto imageData = m_imageHandler->getImage_blocking();
|
||||
|
||||
auto& flipStatus = window.config.flipStatus;
|
||||
++flipStatus.gcQueueNum;
|
||||
@ -196,9 +191,20 @@ class VideoOut: public IVideoOut, private IEventsGraphics {
|
||||
auto const curTime = (uint64_t)(1e9 * timer.getTimeS());
|
||||
|
||||
flipStatus.submitTsc = curTime;
|
||||
|
||||
if (!imageData) {
|
||||
LOG_ERR(L"<- submitFlip(%d):%u %d error", handle, setIndex, index);
|
||||
m_graphics->submitDone();
|
||||
doFlip(window, handle);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DEBUG(L"-> eventDoFlip(%d):%u %d", handle, setIndex, index);
|
||||
transferDisplay(*imageData, displayBufferMeta, waitSema, waitValue);
|
||||
|
||||
// window.config.flipStatus.currentBuffer = index; // set after flip, before vblank
|
||||
|
||||
m_messages.push({MessageType::flip, handle - 1, nullptr, index, setIndex, presentData});
|
||||
m_messages.push({MessageType::flip, handle - 1, nullptr, index, setIndex, *imageData});
|
||||
lock.unlock();
|
||||
m_condSDL2.notify_one();
|
||||
|
||||
@ -208,8 +214,7 @@ class VideoOut: public IVideoOut, private IEventsGraphics {
|
||||
vulkan::QueueInfo* getQueue(vulkan::QueueType type) final;
|
||||
// -
|
||||
|
||||
vulkan::PresentData transferDisplay(vulkan::SwapchainData& swapchain, vulkan::SwapchainData::DisplayBuffers& displayBufferMeta, VkSemaphore waitSema,
|
||||
size_t waitValue);
|
||||
void transferDisplay(ImageData const& imageData, vulkan::SwapchainData::DisplayBuffers& displayBufferMeta, VkSemaphore waitSema, size_t waitValue);
|
||||
|
||||
std::thread createSDLThread();
|
||||
|
||||
@ -290,27 +295,24 @@ VideoOut::~VideoOut() {
|
||||
m_stop = true;
|
||||
m_condSDL2.notify_one();
|
||||
|
||||
for (auto& window: m_windows) {
|
||||
if (window.userId < 0) continue;
|
||||
|
||||
for (size_t n = 0; n < window.config.buffersSetsCount; ++n) {
|
||||
auto& bufferSet = window.config.bufferSets[n];
|
||||
destroySwapchain(m_vulkanObj, bufferSet);
|
||||
}
|
||||
}
|
||||
// printf("VideoOut| waiting on gpu idle\n");
|
||||
m_imageHandler->stop();
|
||||
m_graphics->stop();
|
||||
vkQueueWaitIdle(m_imageHandler->getQueue()->queue);
|
||||
|
||||
// shutdown graphics first (uses vulkan)
|
||||
m_graphics->deinit();
|
||||
m_graphics.reset();
|
||||
|
||||
printf("VideoOut| waiting on gpu idle\n");
|
||||
vkQueueWaitIdle(m_vulkanObj->queues.items[vulkan::getIndex(vulkan::QueueType::present)][0]->queue);
|
||||
|
||||
// printf("VideoOut| Destroy surface\n");
|
||||
// for (auto& window: m_windows) {
|
||||
// if (window.userId < 0) continue;
|
||||
// if (window.surface != nullptr) vkDestroySurfaceKHR(m_vulkanObj->deviceInfo.instance, window.surface, nullptr);
|
||||
// }
|
||||
|
||||
m_imageHandler->deinit();
|
||||
m_imageHandler.reset();
|
||||
|
||||
printf("VideoOut| Destroy vulkan\n");
|
||||
|
||||
deinitVulkan(m_vulkanObj);
|
||||
@ -438,11 +440,10 @@ void VideoOut::removeEvent(int handle, Kernel::EventQueue::IKernelEqueue_t eq, i
|
||||
}
|
||||
}
|
||||
|
||||
vulkan::PresentData VideoOut::transferDisplay(vulkan::SwapchainData& swapchain, vulkan::SwapchainData::DisplayBuffers& displayBufferMeta, VkSemaphore waitSema,
|
||||
size_t waitValue) {
|
||||
auto presentData = vulkan::transfer2Display(&displayBufferMeta, m_vulkanObj, swapchain, m_graphics.get());
|
||||
if (presentData.displayReady != nullptr) vulkan::submitDisplayTransfer(m_vulkanObj, &displayBufferMeta, &presentData, waitSema, waitValue);
|
||||
return presentData;
|
||||
void VideoOut::transferDisplay(ImageData const& imageData, vulkan::SwapchainData::DisplayBuffers& displayBufferMeta, VkSemaphore waitSema, size_t waitValue) {
|
||||
|
||||
vulkan::transfer2Display(&displayBufferMeta, imageData, m_graphics.get());
|
||||
vulkan::submitDisplayTransfer(&displayBufferMeta, imageData, m_imageHandler->getQueue(), waitSema, waitValue);
|
||||
}
|
||||
|
||||
void VideoOut::submitFlip(int handle, int index, int64_t flipArg) {
|
||||
@ -461,13 +462,7 @@ void VideoOut::submitFlip(int handle, int index, int64_t flipArg) {
|
||||
|
||||
LOG_DEBUG(L"-> submitFlip(%d):%u %d", handle, setIndex, index);
|
||||
|
||||
auto const presentData = transferDisplay(swapchain, displayBufferMeta, nullptr, 0);
|
||||
if (presentData.displayReady == nullptr) {
|
||||
LOG_ERR(L"<- submitFlip(%d):%u %d error", handle, setIndex, index);
|
||||
m_graphics->submitDone();
|
||||
doFlip(window, handle);
|
||||
return;
|
||||
}
|
||||
auto imageData = m_imageHandler->getImage_blocking();
|
||||
|
||||
auto& flipStatus = window.config.flipStatus;
|
||||
++flipStatus.gcQueueNum;
|
||||
@ -477,9 +472,18 @@ void VideoOut::submitFlip(int handle, int index, int64_t flipArg) {
|
||||
auto const curTime = (uint64_t)(1e9 * timer.getTimeS());
|
||||
|
||||
flipStatus.submitTsc = curTime;
|
||||
if (!imageData) {
|
||||
LOG_ERR(L"<- submitFlip(%d):%u %d error", handle, setIndex, index);
|
||||
m_graphics->submitDone();
|
||||
doFlip(window, handle);
|
||||
return;
|
||||
}
|
||||
|
||||
transferDisplay(*imageData, displayBufferMeta, nullptr, 0);
|
||||
|
||||
// window.config.flipStatus.currentBuffer = index; // set after flip, before vblank
|
||||
|
||||
m_messages.push({MessageType::flip, handle - 1, nullptr, index, setIndex, presentData});
|
||||
m_messages.push({MessageType::flip, handle - 1, nullptr, index, setIndex, *imageData});
|
||||
lock.unlock();
|
||||
m_condSDL2.notify_one();
|
||||
|
||||
@ -596,7 +600,7 @@ int VideoOut::registerBuffers(int handle, int startIndex, void* const* addresses
|
||||
|
||||
bufferSet.buffers[n].bufferSize = displaySize;
|
||||
bufferSet.buffers[n].bufferAlign = displaySizeAlign;
|
||||
LOG_INFO(L"+bufferset[%d] buffer:%d vaddr:0x%08llx", setIndex, n, (uint64_t)addresses[n]);
|
||||
LOG_INFO(L"+bufferset[%d] buffer:%d vaddr:0x%08llx-0x%08llx", setIndex, n, (uint64_t)addresses[n], (uint64_t)addresses[n] + displaySizeAlign);
|
||||
|
||||
auto [format, colorSpace] = vulkan::getDisplayFormat(m_vulkanObj);
|
||||
if (!m_graphics->registerDisplayBuffer(bufferSet.buffers[n].bufferVaddr, VkExtent2D {.width = _att->width, .height = _att->height}, _att->pitchInPixel,
|
||||
@ -604,7 +608,6 @@ int VideoOut::registerBuffers(int handle, int startIndex, void* const* addresses
|
||||
return -1;
|
||||
}
|
||||
|
||||
createData(m_vulkanObj, m_windows[handle - 1].surface, bufferSet, _att->width, _att->height, accessInitParams()->useVSYNC());
|
||||
return setIndex;
|
||||
}
|
||||
|
||||
@ -724,11 +727,16 @@ std::thread VideoOut::createSDLThread() {
|
||||
auto& info = m_vulkanObj->deviceInfo;
|
||||
|
||||
m_graphics = createGraphics(*this, info.device, info.physicalDevice, info.instance);
|
||||
|
||||
auto queue = m_vulkanObj->queues.items[getIndex(vulkan::QueueType::present)][0].get(); // todo use getQeueu
|
||||
m_imageHandler = createImageHandler(info.device, VkExtent2D {window.config.resolution.paneWidth, window.config.resolution.paneHeight}, queue);
|
||||
m_imageHandler->init(m_vulkanObj, window.surface);
|
||||
|
||||
*item.done = true;
|
||||
} else {
|
||||
vulkan::createSurface(m_vulkanObj, window.window, window.surface);
|
||||
}
|
||||
|
||||
*item.done = true;
|
||||
m_condDone.notify_one();
|
||||
} break;
|
||||
case MessageType::close: {
|
||||
@ -737,15 +745,14 @@ std::thread VideoOut::createSDLThread() {
|
||||
m_condDone.notify_one();
|
||||
} break;
|
||||
case MessageType::flip: {
|
||||
LOG_DEBUG(L"-> flip(%d) set:%u buffer:%u", item.index, item.setIndex, item.presentData.index);
|
||||
LOG_DEBUG(L"-> flip(%d) set:%u buffer:%u", item.index, item.setIndex, item.imageData.index);
|
||||
OPTICK_FRAME("VideoOut");
|
||||
auto& flipStatus = window.config.flipStatus;
|
||||
|
||||
{
|
||||
OPTICK_EVENT("Present");
|
||||
if (!presentImage(m_vulkanObj, window.config.bufferSets[item.setIndex], item.presentData)) {
|
||||
exit(1);
|
||||
}
|
||||
presentImage(item.imageData, m_imageHandler->getSwapchain(), m_imageHandler->getQueue());
|
||||
m_imageHandler->notify_done(item.imageData);
|
||||
}
|
||||
m_graphics->submitDone();
|
||||
|
||||
@ -764,7 +771,7 @@ std::thread VideoOut::createSDLThread() {
|
||||
SDL_SetWindowTitle(window.window, title.c_str());
|
||||
func_pollSDL(window.window);
|
||||
|
||||
LOG_DEBUG(L"<- flip(%d) set:%u buffer:%u", handleIndex, item.setIndex, item.presentData.index);
|
||||
LOG_DEBUG(L"<- flip(%d) set:%u buffer:%u", handleIndex, item.setIndex, item.imageData.index);
|
||||
} break;
|
||||
}
|
||||
m_messages.pop();
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "vulkanHelper.h"
|
||||
|
||||
#include "../imageHandler.h"
|
||||
#include "core/imports/exports/graphics.h"
|
||||
#include "logging.h"
|
||||
#include "utility/utility.h"
|
||||
@ -46,108 +47,7 @@ std::pair<VkFormat, VkColorSpaceKHR> getDisplayFormat(VulkanObj* obj) {
|
||||
return {format, imageColorSpace};
|
||||
}
|
||||
|
||||
void createData(VulkanObj* obj, VkSurfaceKHR surface, vulkan::SwapchainData& swapchainData, uint32_t width, uint32_t height, bool enableVsync) {
|
||||
LOG_USE_MODULE(vulkanHelper);
|
||||
|
||||
uint32_t const numBuffers = swapchainData.buffers.size();
|
||||
|
||||
if (numBuffers > obj->surfaceCapabilities.capabilities.maxImageCount || numBuffers < obj->surfaceCapabilities.capabilities.minImageCount) {
|
||||
LOG_CRIT(L"numBuffers:%d outside %d:%d", numBuffers, obj->surfaceCapabilities.capabilities.minImageCount,
|
||||
obj->surfaceCapabilities.capabilities.maxImageCount);
|
||||
}
|
||||
|
||||
swapchainData.extent2d.width =
|
||||
std::clamp(width, obj->surfaceCapabilities.capabilities.minImageExtent.width, obj->surfaceCapabilities.capabilities.maxImageExtent.width);
|
||||
swapchainData.extent2d.height =
|
||||
std::clamp(height, obj->surfaceCapabilities.capabilities.minImageExtent.height, obj->surfaceCapabilities.capabilities.maxImageExtent.height);
|
||||
|
||||
auto [displayFormat, displayColorSpace] = getDisplayFormat(obj);
|
||||
swapchainData.format = displayFormat;
|
||||
|
||||
VkSwapchainCreateInfoKHR const createInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
.surface = surface,
|
||||
.minImageCount = numBuffers,
|
||||
.imageFormat = swapchainData.format,
|
||||
.imageColorSpace = displayColorSpace,
|
||||
.imageExtent = swapchainData.extent2d,
|
||||
.imageArrayLayers = 1,
|
||||
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
||||
.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.queueFamilyIndexCount = 0,
|
||||
.pQueueFamilyIndices = nullptr,
|
||||
.preTransform = obj->surfaceCapabilities.capabilities.currentTransform,
|
||||
.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
|
||||
.presentMode = enableVsync ? VK_PRESENT_MODE_FIFO_KHR : VK_PRESENT_MODE_IMMEDIATE_KHR,
|
||||
.clipped = VK_TRUE,
|
||||
.oldSwapchain = nullptr,
|
||||
};
|
||||
|
||||
vkCreateSwapchainKHR(obj->deviceInfo.device, &createInfo, nullptr, &swapchainData.swapchain);
|
||||
|
||||
uint32_t numImages = numBuffers;
|
||||
vkGetSwapchainImagesKHR(obj->deviceInfo.device, swapchainData.swapchain, &numImages, nullptr);
|
||||
BOOST_ASSERT_MSG(numImages == numBuffers, "Swapchain created more images");
|
||||
|
||||
{ // Create Semaphore + imageView
|
||||
std::vector<VkImage> images(numImages);
|
||||
vkGetSwapchainImagesKHR(obj->deviceInfo.device, swapchainData.swapchain, &numImages, images.data());
|
||||
|
||||
VkSemaphoreCreateInfo const semCreateInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
|
||||
.pNext = 0,
|
||||
.flags = 0,
|
||||
};
|
||||
|
||||
VkFenceCreateInfo const fenceCreateInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
|
||||
.pNext = 0,
|
||||
.flags = VK_FENCE_CREATE_SIGNALED_BIT,
|
||||
};
|
||||
|
||||
for (uint8_t i = 0; i < numImages; ++i) {
|
||||
auto& buffer = swapchainData.buffers[i];
|
||||
buffer.image = images[i];
|
||||
|
||||
vkCreateSemaphore(obj->deviceInfo.device, &semCreateInfo, nullptr, &buffer.semDisplayReady);
|
||||
vkCreateSemaphore(obj->deviceInfo.device, &semCreateInfo, nullptr, &buffer.semPresentReady);
|
||||
|
||||
vkCreateFence(obj->deviceInfo.device, &fenceCreateInfo, nullptr, &buffer.bufferFence);
|
||||
}
|
||||
}
|
||||
|
||||
// Flip data
|
||||
{
|
||||
VkCommandPoolCreateInfo const poolInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
|
||||
.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
|
||||
.queueFamilyIndex = obj->queues.items[getIndex(QueueType::graphics)][0]->family,
|
||||
};
|
||||
|
||||
if (auto result = vkCreateCommandPool(obj->deviceInfo.device, &poolInfo, nullptr, &swapchainData.commandPool); result != VK_SUCCESS) {
|
||||
LOG_CRIT(L"Couldn't create commandpool(graphics): %d", result);
|
||||
}
|
||||
}
|
||||
{
|
||||
VkCommandBufferAllocateInfo const allocInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
||||
.commandPool = swapchainData.commandPool,
|
||||
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
||||
.commandBufferCount = 1,
|
||||
};
|
||||
|
||||
for (uint8_t i = 0; i < numImages; ++i) {
|
||||
if (auto result = vkAllocateCommandBuffers(obj->deviceInfo.device, &allocInfo, &swapchainData.buffers[i].transferBuffer); result != VK_SUCCESS) {
|
||||
LOG_CRIT(L"Couldn't create commandbuffers(graphics): %d", result);
|
||||
}
|
||||
}
|
||||
}
|
||||
// - Flip Data
|
||||
}
|
||||
|
||||
void submitDisplayTransfer(VulkanObj* obj, SwapchainData::DisplayBuffers const* displayBuffer, PresentData* presentData, VkSemaphore waitSema,
|
||||
void submitDisplayTransfer(SwapchainData::DisplayBuffers const* displayBuffer, ImageData const& imageData, QueueInfo const* queue, VkSemaphore waitSema,
|
||||
size_t waitValue) {
|
||||
LOG_USE_MODULE(vulkanHelper);
|
||||
|
||||
@ -161,9 +61,7 @@ void submitDisplayTransfer(VulkanObj* obj, SwapchainData::DisplayBuffers const*
|
||||
};
|
||||
|
||||
VkPipelineStageFlags waitStage[] = {VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT};
|
||||
VkSemaphore sems[] = {presentData->displayReady, waitSema};
|
||||
|
||||
presentData->presentReady = displayBuffer->semPresentReady;
|
||||
VkSemaphore sems[] = {imageData.semImageReady, waitSema};
|
||||
|
||||
VkSubmitInfo const submitInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
@ -174,78 +72,23 @@ void submitDisplayTransfer(VulkanObj* obj, SwapchainData::DisplayBuffers const*
|
||||
.pWaitDstStageMask = waitStage,
|
||||
|
||||
.commandBufferCount = 1,
|
||||
.pCommandBuffers = &displayBuffer->transferBuffer,
|
||||
.pCommandBuffers = &imageData.cmdBuffer,
|
||||
|
||||
.signalSemaphoreCount = 1,
|
||||
.pSignalSemaphores = &presentData->presentReady,
|
||||
.pSignalSemaphores = &imageData.semImageCopied,
|
||||
};
|
||||
|
||||
{
|
||||
auto& queue = obj->queues.items[getIndex(QueueType::present)][0];
|
||||
|
||||
std::unique_lock lock(queue->mutex);
|
||||
if (VkResult result = vkQueueSubmit(queue->queue, 1, &submitInfo, displayBuffer->bufferFence); result != VK_SUCCESS) {
|
||||
if (VkResult result = vkQueueSubmit(queue->queue, 1, &submitInfo, nullptr); result != VK_SUCCESS) {
|
||||
LOG_CRIT(L"Couldn't vkQueueSubmit Transfer %S", string_VkResult(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PresentData transfer2Display(SwapchainData::DisplayBuffers const* displayBuffer, VulkanObj* obj, vulkan::SwapchainData& swapchain, IGraphics* graphics) {
|
||||
void transfer2Display(SwapchainData::DisplayBuffers const* displayBuffer, ImageData const& imageData, IGraphics* graphics) {
|
||||
LOG_USE_MODULE(vulkanHelper);
|
||||
|
||||
// Wait on prev present (only one image is allowed )
|
||||
{
|
||||
boost::unique_lock lock(swapchain.mutexPresent);
|
||||
swapchain.condPresent.wait(lock, [&swapchain] { return swapchain.waitId == swapchain.presentId; });
|
||||
++swapchain.waitId;
|
||||
}
|
||||
// -
|
||||
|
||||
PresentData presentData;
|
||||
|
||||
// Get swapchain image
|
||||
presentData.displayReady = displayBuffer->semDisplayReady;
|
||||
{
|
||||
int n = 2;
|
||||
VkResult result = VK_SUCCESS;
|
||||
for (; n >= 0; --n) {
|
||||
if (result = vkAcquireNextImageKHR(obj->deviceInfo.device, swapchain.swapchain, UINT64_MAX, presentData.displayReady, VK_NULL_HANDLE, &presentData.index);
|
||||
result != VK_SUCCESS) {
|
||||
if (result == VK_NOT_READY) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
}
|
||||
} else
|
||||
break;
|
||||
}
|
||||
if (n <= 0) {
|
||||
LOG_ERR(L"vkAcquireNextImageKHR %S", string_VkResult(result));
|
||||
swapchain.waitId--; // would deadlock on next call
|
||||
return {};
|
||||
}
|
||||
}
|
||||
presentData.swapchainImage = swapchain.buffers[presentData.index].image;
|
||||
// -
|
||||
|
||||
vkWaitForFences(obj->deviceInfo.device, 1, &displayBuffer->bufferFence, VK_TRUE, UINT64_MAX);
|
||||
vkResetFences(obj->deviceInfo.device, 1, &displayBuffer->bufferFence);
|
||||
|
||||
auto cmdBuffer = displayBuffer->transferBuffer;
|
||||
|
||||
// Wait and begin command buffer
|
||||
vkResetCommandBuffer(cmdBuffer, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT);
|
||||
|
||||
// Transfer
|
||||
VkCommandBufferBeginInfo const beginInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
|
||||
.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT,
|
||||
.pInheritanceInfo = nullptr,
|
||||
};
|
||||
|
||||
if (vkBeginCommandBuffer(cmdBuffer, &beginInfo) != VK_SUCCESS) {
|
||||
LOG_CRIT(L"Error vkBeginCommandBuffer");
|
||||
}
|
||||
// - begin command buffer
|
||||
|
||||
{
|
||||
VkImageMemoryBarrier const barrier {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
@ -257,13 +100,13 @@ PresentData transfer2Display(SwapchainData::DisplayBuffers const* displayBuffer,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
|
||||
.image = presentData.swapchainImage,
|
||||
.image = imageData.swapchainImage,
|
||||
.subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .baseMipLevel = 0, .levelCount = 1, .baseArrayLayer = 0, .layerCount = 1}};
|
||||
|
||||
vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
vkCmdPipelineBarrier(imageData.cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
}
|
||||
|
||||
graphics->copyDisplayBuffer(displayBuffer->bufferVaddr, cmdBuffer, presentData.swapchainImage, swapchain.extent2d); // let gpumemorymanager decide
|
||||
graphics->copyDisplayBuffer(displayBuffer->bufferVaddr, imageData.cmdBuffer, imageData.swapchainImage, imageData.extent); // let gpumemorymanager decide
|
||||
|
||||
{
|
||||
// Change to Present Layout
|
||||
@ -277,50 +120,41 @@ PresentData transfer2Display(SwapchainData::DisplayBuffers const* displayBuffer,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
|
||||
.image = presentData.swapchainImage,
|
||||
.image = imageData.swapchainImage,
|
||||
.subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .baseMipLevel = 0, .levelCount = 1, .baseArrayLayer = 0, .layerCount = 1}};
|
||||
|
||||
vkCmdPipelineBarrier(cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
vkCmdPipelineBarrier(imageData.cmdBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
|
||||
}
|
||||
// - Present layout
|
||||
|
||||
// End CmdBuffer -> Submit
|
||||
if (vkEndCommandBuffer(cmdBuffer) != VK_SUCCESS) {
|
||||
if (vkEndCommandBuffer(imageData.cmdBuffer) != VK_SUCCESS) {
|
||||
LOG_CRIT(L"Couldn't end commandbuffer");
|
||||
}
|
||||
// -
|
||||
|
||||
return presentData;
|
||||
}
|
||||
|
||||
bool presentImage(VulkanObj* obj, vulkan::SwapchainData& swapchain, vulkan::PresentData const& presentData) {
|
||||
void presentImage(ImageData const& imageData, VkSwapchainKHR swapchain, QueueInfo const* queue) {
|
||||
LOG_USE_MODULE(vulkanHelper);
|
||||
|
||||
VkPresentInfoKHR const presentInfo {
|
||||
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
|
||||
.pNext = nullptr,
|
||||
.waitSemaphoreCount = 1,
|
||||
.pWaitSemaphores = &presentData.presentReady,
|
||||
.pWaitSemaphores = &imageData.semImageCopied,
|
||||
.swapchainCount = 1,
|
||||
.pSwapchains = &swapchain.swapchain,
|
||||
.pImageIndices = &presentData.index,
|
||||
.pSwapchains = &swapchain,
|
||||
.pImageIndices = &imageData.index,
|
||||
.pResults = nullptr,
|
||||
};
|
||||
|
||||
{
|
||||
OPTICK_GPU_FLIP(&swapchain.swapchain);
|
||||
OPTICK_GPU_FLIP(&swapchain);
|
||||
OPTICK_CATEGORY("Present", Optick::Category::Wait);
|
||||
|
||||
auto& queue = obj->queues.items[getIndex(QueueType::present)][0];
|
||||
|
||||
std::unique_lock lock(queue->mutex);
|
||||
vkQueuePresentKHR(queue->queue, &presentInfo);
|
||||
}
|
||||
|
||||
++swapchain.presentId;
|
||||
swapchain.condPresent.notify_all();
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace vulkan
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <functional>
|
||||
|
||||
class IGraphics;
|
||||
struct ImageData;
|
||||
|
||||
namespace vulkan {
|
||||
struct PresentData {
|
||||
@ -14,12 +15,13 @@ struct PresentData {
|
||||
uint32_t index = 0;
|
||||
};
|
||||
|
||||
void submitDisplayTransfer(VulkanObj* obj, SwapchainData::DisplayBuffers const* displayBuffer, PresentData* presentData, VkSemaphore waitSema,
|
||||
std::pair<VkFormat, VkColorSpaceKHR> getDisplayFormat(VulkanObj* obj);
|
||||
|
||||
void submitDisplayTransfer(SwapchainData::DisplayBuffers const* displayBuffer, ImageData const& imageData, QueueInfo const* queue, VkSemaphore waitSema,
|
||||
size_t waitValue);
|
||||
|
||||
PresentData transfer2Display(SwapchainData::DisplayBuffers const* displayBuffer, VulkanObj* obj, vulkan::SwapchainData& swapchain, IGraphics* graphics);
|
||||
void transfer2Display(SwapchainData::DisplayBuffers const* displayBuffer, ImageData const& imageData, IGraphics* graphics);
|
||||
|
||||
bool presentImage(VulkanObj* obj, SwapchainData& swapchain, vulkan::PresentData const& presentData);
|
||||
void presentImage(ImageData const& imageData, VkSwapchainKHR swapchain, QueueInfo const* queue);
|
||||
|
||||
void waitFlipped(VulkanObj* obj); /// Call before submit
|
||||
} // namespace vulkan
|
||||
|
@ -774,16 +774,4 @@ void deinitVulkan(VulkanObj* obj) {
|
||||
|
||||
delete obj;
|
||||
}
|
||||
|
||||
void destroySwapchain(VulkanObj* obj, SwapchainData& swapchainData) {
|
||||
for (auto& item: swapchainData.buffers) {
|
||||
vkDestroySemaphore(obj->deviceInfo.device, item.semDisplayReady, nullptr);
|
||||
vkDestroySemaphore(obj->deviceInfo.device, item.semPresentReady, nullptr);
|
||||
vkDestroyFence(obj->deviceInfo.device, item.bufferFence, nullptr);
|
||||
// vkDestroyImage(obj->deviceInfo.device, item.image, nullptr); // swapchain does that
|
||||
}
|
||||
|
||||
vkDestroyCommandPool(obj->deviceInfo.device, swapchainData.commandPool, nullptr);
|
||||
// vkDestroySwapchainKHR(obj->deviceInfo.device, swapchainData.swapchain, nullptr); // still chrashed despite waiting for idle
|
||||
}
|
||||
} // namespace vulkan
|
||||
|
@ -37,7 +37,7 @@ struct QueueInfo {
|
||||
uint32_t family = 0;
|
||||
size_t useCount = 0;
|
||||
|
||||
std::mutex mutex; // sync queue submit access
|
||||
mutable std::mutex mutex; // sync queue submit access
|
||||
|
||||
QueueInfo(VkQueue queue_, uint32_t family_): queue(queue_), family(family_) {}
|
||||
};
|
||||
@ -47,34 +47,13 @@ struct Queues {
|
||||
};
|
||||
|
||||
struct SwapchainData {
|
||||
VkSwapchainKHR swapchain = nullptr;
|
||||
VkFormat format = VK_FORMAT_UNDEFINED;
|
||||
VkExtent2D extent2d = {};
|
||||
|
||||
// present sync
|
||||
uint64_t presentId = 0;
|
||||
uint64_t waitId = 0;
|
||||
|
||||
boost::mutex mutexPresent;
|
||||
boost::condition_variable condPresent;
|
||||
|
||||
// -
|
||||
|
||||
struct DisplayBuffers {
|
||||
uint64_t bufferVaddr = 0;
|
||||
uint32_t bufferSize = 0;
|
||||
uint32_t bufferAlign = 0;
|
||||
|
||||
VkImage image;
|
||||
VkSemaphore semDisplayReady;
|
||||
|
||||
VkCommandBuffer transferBuffer;
|
||||
VkSemaphore semPresentReady;
|
||||
|
||||
VkFence bufferFence;
|
||||
};
|
||||
|
||||
VkCommandPool commandPool;
|
||||
std::vector<DisplayBuffers> buffers;
|
||||
};
|
||||
|
||||
@ -107,7 +86,4 @@ VkInstance const getVkInstance();
|
||||
std::string_view const getGPUName();
|
||||
|
||||
std::pair<VkFormat, VkColorSpaceKHR> getDisplayFormat(VulkanObj* obj);
|
||||
void createData(VulkanObj* obj, VkSurfaceKHR surface, SwapchainData& swapchainData, uint32_t width, uint32_t height, bool enableVsync); // Swapchain
|
||||
void destroySwapchain(VulkanObj* obj, SwapchainData& swapchainData);
|
||||
|
||||
} // namespace vulkan
|
||||
|
22
docs/uml/modules/videout_swapchain.puml
Normal file
22
docs/uml/modules/videout_swapchain.puml
Normal file
@ -0,0 +1,22 @@
|
||||
@startuml
|
||||
skinparam classAttributeIconSize 0
|
||||
|
||||
interface IImageHandler{
|
||||
+ {abstract} ImageData getImage_blocking()
|
||||
+ {abstract} void notify_done(ImageData)
|
||||
}
|
||||
|
||||
class ImageHandler{
|
||||
|
||||
}
|
||||
|
||||
class ImageData
|
||||
|
||||
IImageHandler <|-- ImageHandler
|
||||
IImageHandler - ImageData
|
||||
|
||||
class VideoOut << (S,#FF7700) Singleton >> {}
|
||||
VideoOut *-ImageHandler
|
||||
|
||||
user ()- IImageHandler
|
||||
@enduml
|
@ -202,13 +202,6 @@ int SYSV_ABI sceGnmDrawIndexAuto(uint32_t* cmdOut, uint64_t size, uint32_t index
|
||||
|
||||
int32_t SYSV_ABI sceGnmValidateDrawCommandBuffers(uint32_t count, void* dcbGpuAddrs[], uint32_t* dcbSizesInBytes, void* ccbGpuAddrs[],
|
||||
uint32_t* ccbSizesInBytes) {
|
||||
#if DEBUG
|
||||
LOG_USE_MODULE(libSceGraphicsDriver);
|
||||
for (uint32_t n = 0; n < count; ++n) {
|
||||
if (dcbGpuAddrs != nullptr) LOG_DEBUG(L"Validate DCB[%d] 0x%08llx(0x%u)", n, (uint64_t)dcbGpuAddrs[n], dcbSizesInBytes[n]);
|
||||
if (ccbGpuAddrs != nullptr) LOG_DEBUG(L"Validate CCB[%d] 0x%08llx(0x%u)", n, (uint64_t)ccbGpuAddrs[n], ccbSizesInBytes[n]);
|
||||
}
|
||||
#endif
|
||||
return Err::VALIDATION_NOT_ENABLED;
|
||||
}
|
||||
|
||||
@ -415,8 +408,8 @@ uint64_t SYSV_ABI sceGnmGetGpuCoreClockFrequency() {
|
||||
return 0x800000000;
|
||||
}
|
||||
|
||||
int SYSV_ABI sceGnmIsUserPaEnabled() {
|
||||
return 0;
|
||||
bool SYSV_ABI sceGnmIsUserPaEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void* SYSV_ABI sceGnmGetTheTessellationFactorRingBufferBaseAddress() {
|
||||
@ -512,7 +505,7 @@ SceWorkloadStatus SYSV_ABI sceGnmCreateWorkloadStream(const char* name, SceWorkl
|
||||
SceWorkloadStatus SYSV_ABI sceGnmBeginWorkload(SceWorkloadStream stream, uint64_t* workload) {
|
||||
static int32_t count = 0;
|
||||
*workload = ++count;
|
||||
return SceWorkloadStatus::StatusOk;
|
||||
return SceWorkloadStatus::StatusInvalidPointer;
|
||||
}
|
||||
|
||||
SceWorkloadStatus SYSV_ABI sceGnmEndWorkload(uint64_t workload) {
|
||||
|
@ -100,7 +100,6 @@ EXPORT SYSV_ABI int32_t sceVideoOutGetVblankStatus(int32_t handle, SceVideoOutVb
|
||||
|
||||
EXPORT SYSV_ABI int32_t sceVideoOutIsFlipPending(int32_t handle) {
|
||||
return accessVideoOut().getPendingFlips(handle);
|
||||
;
|
||||
}
|
||||
|
||||
EXPORT SYSV_ABI int32_t sceVideoOutGetResolutionStatus(int32_t handle, SceVideoOutResolutionStatus* status) {
|
||||
@ -190,7 +189,7 @@ EXPORT SYSV_ABI int32_t sceVideoOutGetEventData(Kernel::EventQueue::KernelEvent_
|
||||
}
|
||||
|
||||
EXPORT SYSV_ABI int32_t sceVideoOutGetEventCount(Kernel::EventQueue::KernelEvent_t ev) {
|
||||
return Ok;
|
||||
return ev->fflags;
|
||||
}
|
||||
|
||||
EXPORT SYSV_ABI int32_t sceVideoOutWaitVblank(int32_t handle) {
|
||||
|
1
out/docs/uml/modules/videout_swapchain.svg
Normal file
1
out/docs/uml/modules/videout_swapchain.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 9.8 KiB |
Loading…
Reference in New Issue
Block a user