2019-09-12 15:28:40 -04:00
|
|
|
#include <cstring>
|
|
|
|
#include "../GsPixelFormats.h"
|
|
|
|
#include "../../Log.h"
|
|
|
|
#include "GSH_Vulkan.h"
|
2021-09-24 21:59:21 -04:00
|
|
|
#include "GSH_VulkanPlatformDefs.h"
|
2021-09-14 17:24:42 -04:00
|
|
|
#include "GSH_VulkanDrawDesktop.h"
|
2021-06-20 15:13:21 -04:00
|
|
|
#include "GSH_VulkanDrawMobile.h"
|
2020-04-28 13:26:23 -04:00
|
|
|
#include "GSH_VulkanDeviceInfo.h"
|
2019-09-15 12:45:04 -04:00
|
|
|
#include "vulkan/StructDefs.h"
|
2021-09-22 19:23:45 -04:00
|
|
|
#include "vulkan/StructChain.h"
|
2019-09-25 19:42:24 -04:00
|
|
|
#include "vulkan/Utils.h"
|
2019-09-12 15:28:40 -04:00
|
|
|
|
|
|
|
#define LOG_NAME ("gsh_vulkan")
|
|
|
|
|
2019-09-21 18:41:41 -04:00
|
|
|
using namespace GSH_Vulkan;
|
|
|
|
|
2019-10-01 12:31:49 -04:00
|
|
|
static uint32 MakeColor(uint8 r, uint8 g, uint8 b, uint8 a)
|
|
|
|
{
|
|
|
|
return (a << 24) | (b << 16) | (g << 8) | (r);
|
|
|
|
}
|
|
|
|
|
2020-01-08 12:52:17 -05:00
|
|
|
static uint16 RGBA32ToRGBA16(uint32 inputColor)
|
|
|
|
{
|
|
|
|
uint32 result = 0;
|
2020-01-31 09:34:48 -05:00
|
|
|
result |= ((inputColor & 0x000000F8) >> (0 + 3)) << 0;
|
|
|
|
result |= ((inputColor & 0x0000F800) >> (8 + 3)) << 5;
|
2020-01-08 12:52:17 -05:00
|
|
|
result |= ((inputColor & 0x00F80000) >> (16 + 3)) << 10;
|
2020-01-31 09:34:48 -05:00
|
|
|
result |= ((inputColor & 0x80000000) >> 31) << 15;
|
2020-01-08 12:52:17 -05:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-12-11 20:18:07 -05:00
|
|
|
template <typename StorageFormat>
|
|
|
|
static Framework::Vulkan::CImage CreateSwizzleTable(Framework::Vulkan::CDevice& device,
|
2019-12-13 23:21:59 -05:00
|
|
|
const VkPhysicalDeviceMemoryProperties& memoryProperties, VkQueue queue, Framework::Vulkan::CCommandBufferPool& commandBufferPool)
|
2019-12-11 20:18:07 -05:00
|
|
|
{
|
|
|
|
auto result = Framework::Vulkan::CImage(device, memoryProperties,
|
2019-12-13 23:21:59 -05:00
|
|
|
VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
|
|
|
|
VK_FORMAT_R32_UINT, StorageFormat::PAGEWIDTH, StorageFormat::PAGEHEIGHT);
|
2019-12-11 20:18:07 -05:00
|
|
|
result.Fill(queue, commandBufferPool, memoryProperties,
|
2019-12-13 23:21:59 -05:00
|
|
|
CGsPixelFormats::CPixelIndexor<StorageFormat>::GetPageOffsets());
|
2019-12-11 20:18:07 -05:00
|
|
|
result.SetLayout(queue, commandBufferPool,
|
2021-07-15 12:42:35 -04:00
|
|
|
VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_READ_BIT);
|
2019-12-11 20:18:07 -05:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-09-12 15:28:40 -04:00
|
|
|
CGSH_Vulkan::CGSH_Vulkan()
|
|
|
|
{
|
2019-09-21 18:41:41 -04:00
|
|
|
m_context = std::make_shared<CContext>();
|
2019-09-12 15:28:40 -04:00
|
|
|
}
|
|
|
|
|
2020-04-29 17:52:20 -04:00
|
|
|
Framework::Vulkan::CInstance CGSH_Vulkan::CreateInstance(bool useValidationLayers)
|
2020-04-25 20:42:42 -04:00
|
|
|
{
|
|
|
|
auto instanceCreateInfo = Framework::Vulkan::InstanceCreateInfo();
|
|
|
|
|
|
|
|
std::vector<const char*> extensions;
|
|
|
|
extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
|
2021-09-28 10:57:17 -04:00
|
|
|
extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
|
2020-04-25 20:42:42 -04:00
|
|
|
#ifdef _WIN32
|
|
|
|
extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
|
|
|
|
#endif
|
|
|
|
#ifdef __APPLE__
|
2021-06-29 08:14:27 -04:00
|
|
|
#if TARGET_OS_IPHONE
|
|
|
|
extensions.push_back(VK_MVK_IOS_SURFACE_EXTENSION_NAME);
|
|
|
|
#else
|
|
|
|
extensions.push_back(VK_MVK_MACOS_SURFACE_EXTENSION_NAME);
|
|
|
|
#endif
|
2020-04-25 20:42:42 -04:00
|
|
|
#endif
|
|
|
|
#ifdef __linux__
|
2021-07-13 15:26:31 -04:00
|
|
|
#ifdef __ANDROID__
|
|
|
|
extensions.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME);
|
|
|
|
#else
|
|
|
|
extensions.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
|
|
|
|
#endif
|
2020-04-25 20:42:42 -04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
std::vector<const char*> layers;
|
|
|
|
#if defined(_DEBUG) && !defined(__APPLE__)
|
2020-04-29 17:52:20 -04:00
|
|
|
if(useValidationLayers)
|
|
|
|
{
|
2021-03-08 12:26:33 -05:00
|
|
|
layers.push_back("VK_LAYER_KHRONOS_validation");
|
2020-04-29 17:52:20 -04:00
|
|
|
}
|
2020-04-25 20:42:42 -04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
auto appInfo = Framework::Vulkan::ApplicationInfo();
|
|
|
|
appInfo.pApplicationName = "Play!";
|
|
|
|
appInfo.pEngineName = "Play!";
|
2021-09-24 21:59:21 -04:00
|
|
|
#if GSH_VULKAN_IS_DESKTOP
|
|
|
|
appInfo.apiVersion = VK_API_VERSION_1_2;
|
|
|
|
#elif GSH_VULKAN_IS_MOBILE
|
2021-06-27 09:54:51 -04:00
|
|
|
appInfo.apiVersion = VK_API_VERSION_1_0;
|
2021-09-24 21:59:21 -04:00
|
|
|
#else
|
|
|
|
#error Unsupported Vulkan flavor
|
|
|
|
#endif
|
2021-09-25 10:31:27 -04:00
|
|
|
|
2020-04-25 20:42:42 -04:00
|
|
|
instanceCreateInfo.pApplicationInfo = &appInfo;
|
|
|
|
instanceCreateInfo.enabledExtensionCount = extensions.size();
|
|
|
|
instanceCreateInfo.ppEnabledExtensionNames = extensions.data();
|
|
|
|
instanceCreateInfo.enabledLayerCount = layers.size();
|
|
|
|
instanceCreateInfo.ppEnabledLayerNames = layers.data();
|
|
|
|
return Framework::Vulkan::CInstance(instanceCreateInfo);
|
|
|
|
}
|
|
|
|
|
2019-09-12 15:28:40 -04:00
|
|
|
void CGSH_Vulkan::InitializeImpl()
|
|
|
|
{
|
2019-12-13 17:18:06 -05:00
|
|
|
assert(!m_instance.IsEmpty());
|
|
|
|
m_context->instance = &m_instance;
|
2019-09-12 15:28:40 -04:00
|
|
|
|
|
|
|
auto physicalDevices = GetPhysicalDevices();
|
|
|
|
assert(!physicalDevices.empty());
|
2020-04-28 13:26:23 -04:00
|
|
|
auto physicalDeviceIndex = GetPhysicalDeviceIndex(physicalDevices);
|
|
|
|
m_context->physicalDevice = physicalDevices[physicalDeviceIndex];
|
2019-09-12 15:28:40 -04:00
|
|
|
|
2019-12-13 17:18:06 -05:00
|
|
|
auto renderQueueFamilies = GetRenderQueueFamilies(m_context->physicalDevice);
|
2019-09-12 17:17:10 -04:00
|
|
|
assert(!renderQueueFamilies.empty());
|
|
|
|
auto renderQueueFamily = renderQueueFamilies[0];
|
|
|
|
|
2019-12-13 17:18:06 -05:00
|
|
|
m_instance.vkGetPhysicalDeviceMemoryProperties(m_context->physicalDevice, &m_context->physicalDeviceMemoryProperties);
|
2019-09-20 09:19:58 -04:00
|
|
|
|
2021-08-18 19:26:40 -04:00
|
|
|
if(m_context->surface)
|
|
|
|
{
|
|
|
|
auto surfaceFormats = GetDeviceSurfaceFormats(m_context->physicalDevice);
|
|
|
|
assert(surfaceFormats.size() > 0);
|
|
|
|
m_context->surfaceFormat = surfaceFormats[0];
|
|
|
|
}
|
2019-09-15 10:56:53 -04:00
|
|
|
|
2019-12-13 17:18:06 -05:00
|
|
|
CreateDevice(m_context->physicalDevice);
|
2019-09-21 18:41:41 -04:00
|
|
|
m_context->device.vkGetDeviceQueue(m_context->device, renderQueueFamily, 0, &m_context->queue);
|
|
|
|
m_context->commandBufferPool = Framework::Vulkan::CCommandBufferPool(m_context->device, renderQueueFamily);
|
2019-09-12 15:28:40 -04:00
|
|
|
|
2019-09-24 12:35:31 -04:00
|
|
|
CreateDescriptorPool();
|
2019-12-17 19:22:27 -05:00
|
|
|
CreateMemoryBuffer();
|
2020-02-17 13:21:50 -05:00
|
|
|
CreateClutBuffer();
|
2019-09-25 19:42:24 -04:00
|
|
|
|
2019-12-11 20:18:07 -05:00
|
|
|
m_swizzleTablePSMCT32 = CreateSwizzleTable<CGsPixelFormats::STORAGEPSMCT32>(m_context->device, m_context->physicalDeviceMemoryProperties, m_context->queue, m_context->commandBufferPool);
|
2019-12-15 12:17:43 -05:00
|
|
|
m_swizzleTablePSMCT16 = CreateSwizzleTable<CGsPixelFormats::STORAGEPSMCT16>(m_context->device, m_context->physicalDeviceMemoryProperties, m_context->queue, m_context->commandBufferPool);
|
|
|
|
m_swizzleTablePSMCT16S = CreateSwizzleTable<CGsPixelFormats::STORAGEPSMCT16S>(m_context->device, m_context->physicalDeviceMemoryProperties, m_context->queue, m_context->commandBufferPool);
|
2019-12-13 23:21:59 -05:00
|
|
|
m_swizzleTablePSMT8 = CreateSwizzleTable<CGsPixelFormats::STORAGEPSMT8>(m_context->device, m_context->physicalDeviceMemoryProperties, m_context->queue, m_context->commandBufferPool);
|
2019-12-15 12:17:43 -05:00
|
|
|
m_swizzleTablePSMT4 = CreateSwizzleTable<CGsPixelFormats::STORAGEPSMT4>(m_context->device, m_context->physicalDeviceMemoryProperties, m_context->queue, m_context->commandBufferPool);
|
2019-12-22 16:35:58 -05:00
|
|
|
m_swizzleTablePSMZ32 = CreateSwizzleTable<CGsPixelFormats::STORAGEPSMZ32>(m_context->device, m_context->physicalDeviceMemoryProperties, m_context->queue, m_context->commandBufferPool);
|
2020-03-04 19:27:03 -05:00
|
|
|
m_swizzleTablePSMZ16 = CreateSwizzleTable<CGsPixelFormats::STORAGEPSMZ16>(m_context->device, m_context->physicalDeviceMemoryProperties, m_context->queue, m_context->commandBufferPool);
|
2019-12-11 20:18:07 -05:00
|
|
|
|
2021-07-15 12:42:35 -04:00
|
|
|
m_context->swizzleTablePSMCT32View = m_swizzleTablePSMCT32.CreateImageView();
|
|
|
|
m_context->swizzleTablePSMCT16View = m_swizzleTablePSMCT16.CreateImageView();
|
|
|
|
m_context->swizzleTablePSMCT16SView = m_swizzleTablePSMCT16S.CreateImageView();
|
|
|
|
m_context->swizzleTablePSMT8View = m_swizzleTablePSMT8.CreateImageView();
|
|
|
|
m_context->swizzleTablePSMT4View = m_swizzleTablePSMT4.CreateImageView();
|
|
|
|
m_context->swizzleTablePSMZ32View = m_swizzleTablePSMZ32.CreateImageView();
|
|
|
|
m_context->swizzleTablePSMZ16View = m_swizzleTablePSMZ16.CreateImageView();
|
2019-12-11 20:18:07 -05:00
|
|
|
|
2019-12-10 09:39:12 -05:00
|
|
|
m_frameCommandBuffer = std::make_shared<CFrameCommandBuffer>(m_context);
|
|
|
|
m_clutLoad = std::make_shared<CClutLoad>(m_context, m_frameCommandBuffer);
|
2021-09-24 21:59:21 -04:00
|
|
|
#if GSH_VULKAN_IS_DESKTOP
|
|
|
|
m_draw = std::make_shared<CDrawDesktop>(m_context, m_frameCommandBuffer);
|
|
|
|
#elif GSH_VULKAN_IS_MOBILE
|
2021-06-20 15:13:21 -04:00
|
|
|
m_draw = std::make_shared<CDrawMobile>(m_context, m_frameCommandBuffer);
|
2021-09-24 21:59:21 -04:00
|
|
|
#else
|
|
|
|
#error Unsupported Vulkan flavor
|
|
|
|
#endif
|
2021-08-18 19:26:40 -04:00
|
|
|
if(m_context->surface)
|
|
|
|
{
|
|
|
|
m_present = std::make_shared<CPresent>(m_context);
|
|
|
|
}
|
2020-02-12 19:41:35 -05:00
|
|
|
m_transferHost = std::make_shared<CTransferHost>(m_context, m_frameCommandBuffer);
|
2020-02-12 09:24:59 -05:00
|
|
|
m_transferLocal = std::make_shared<CTransferLocal>(m_context, m_frameCommandBuffer);
|
2019-12-10 09:39:12 -05:00
|
|
|
|
|
|
|
m_frameCommandBuffer->RegisterWriter(m_draw.get());
|
2020-02-12 19:41:35 -05:00
|
|
|
m_frameCommandBuffer->RegisterWriter(m_transferHost.get());
|
2020-01-16 21:46:02 -05:00
|
|
|
m_frameCommandBuffer->BeginFrame();
|
2019-09-12 15:28:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void CGSH_Vulkan::ReleaseImpl()
|
|
|
|
{
|
|
|
|
ResetImpl();
|
2019-12-13 23:21:59 -05:00
|
|
|
|
2019-09-18 13:35:20 -04:00
|
|
|
//Flush any pending rendering commands
|
2019-09-21 18:41:41 -04:00
|
|
|
m_context->device.vkQueueWaitIdle(m_context->queue);
|
2019-09-18 13:35:20 -04:00
|
|
|
|
2019-12-05 18:43:54 -05:00
|
|
|
m_clutLoad.reset();
|
2019-10-01 12:31:49 -04:00
|
|
|
m_draw.reset();
|
2019-09-21 18:41:41 -04:00
|
|
|
m_present.reset();
|
2020-02-12 19:41:35 -05:00
|
|
|
m_transferHost.reset();
|
2020-02-12 09:24:59 -05:00
|
|
|
m_transferLocal.reset();
|
2019-12-10 09:39:12 -05:00
|
|
|
m_frameCommandBuffer.reset();
|
2019-09-19 15:42:00 -04:00
|
|
|
|
2019-12-11 20:18:07 -05:00
|
|
|
m_context->device.vkDestroyImageView(m_context->device, m_context->swizzleTablePSMCT32View, nullptr);
|
2019-12-15 12:17:43 -05:00
|
|
|
m_context->device.vkDestroyImageView(m_context->device, m_context->swizzleTablePSMCT16View, nullptr);
|
|
|
|
m_context->device.vkDestroyImageView(m_context->device, m_context->swizzleTablePSMCT16SView, nullptr);
|
2019-12-11 20:18:07 -05:00
|
|
|
m_context->device.vkDestroyImageView(m_context->device, m_context->swizzleTablePSMT8View, nullptr);
|
2019-12-15 12:17:43 -05:00
|
|
|
m_context->device.vkDestroyImageView(m_context->device, m_context->swizzleTablePSMT4View, nullptr);
|
2019-12-22 16:35:58 -05:00
|
|
|
m_context->device.vkDestroyImageView(m_context->device, m_context->swizzleTablePSMZ32View, nullptr);
|
2020-03-04 19:27:03 -05:00
|
|
|
m_context->device.vkDestroyImageView(m_context->device, m_context->swizzleTablePSMZ16View, nullptr);
|
2019-12-11 20:18:07 -05:00
|
|
|
|
|
|
|
m_swizzleTablePSMCT32.Reset();
|
2019-12-15 12:17:43 -05:00
|
|
|
m_swizzleTablePSMCT16.Reset();
|
|
|
|
m_swizzleTablePSMCT16S.Reset();
|
2019-12-11 20:18:07 -05:00
|
|
|
m_swizzleTablePSMT8.Reset();
|
2019-12-15 12:17:43 -05:00
|
|
|
m_swizzleTablePSMT4.Reset();
|
2019-12-22 16:35:58 -05:00
|
|
|
m_swizzleTablePSMZ32.Reset();
|
2020-03-04 19:27:03 -05:00
|
|
|
m_swizzleTablePSMZ16.Reset();
|
2019-12-13 23:21:59 -05:00
|
|
|
|
2019-09-24 12:35:31 -04:00
|
|
|
m_context->device.vkDestroyDescriptorPool(m_context->device, m_context->descriptorPool, nullptr);
|
2020-02-17 13:21:50 -05:00
|
|
|
m_context->clutBuffer.Reset();
|
2019-12-17 19:22:27 -05:00
|
|
|
m_context->memoryBuffer.Reset();
|
2021-04-12 11:42:42 -04:00
|
|
|
m_context->memoryBufferCopy.Reset();
|
2019-09-21 18:41:41 -04:00
|
|
|
m_context->commandBufferPool.Reset();
|
|
|
|
m_context->device.Reset();
|
2021-03-30 13:50:52 -04:00
|
|
|
|
|
|
|
delete[] m_memoryCache;
|
|
|
|
m_memoryCache = nullptr;
|
2019-09-12 15:28:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void CGSH_Vulkan::ResetImpl()
|
|
|
|
{
|
2019-10-01 12:31:49 -04:00
|
|
|
m_vtxCount = 0;
|
|
|
|
m_primitiveType = PRIM_INVALID;
|
2020-02-18 13:06:13 -05:00
|
|
|
memset(&m_clutStates, 0, sizeof(m_clutStates));
|
2019-09-12 15:28:40 -04:00
|
|
|
}
|
|
|
|
|
2020-01-24 12:43:00 -05:00
|
|
|
void CGSH_Vulkan::SetPresentationParams(const CGSHandler::PRESENTATION_PARAMS& presentationParams)
|
|
|
|
{
|
|
|
|
CGSHandler::SetPresentationParams(presentationParams);
|
|
|
|
m_present->ValidateSwapChain(presentationParams);
|
|
|
|
}
|
|
|
|
|
2020-01-12 21:47:24 -05:00
|
|
|
void CGSH_Vulkan::MarkNewFrame()
|
|
|
|
{
|
2020-01-16 21:46:02 -05:00
|
|
|
m_drawCallCount = m_frameCommandBuffer->GetFlushCount();
|
|
|
|
m_frameCommandBuffer->ResetFlushCount();
|
|
|
|
m_frameCommandBuffer->EndFrame();
|
2020-01-12 21:47:24 -05:00
|
|
|
m_frameCommandBuffer->BeginFrame();
|
2021-08-18 17:16:25 -04:00
|
|
|
CGSHandler::MarkNewFrame();
|
2020-01-12 21:47:24 -05:00
|
|
|
}
|
|
|
|
|
2019-09-12 15:28:40 -04:00
|
|
|
void CGSH_Vulkan::FlipImpl()
|
|
|
|
{
|
2020-01-25 18:50:54 -05:00
|
|
|
auto dispInfo = GetCurrentDisplayInfo();
|
|
|
|
auto fb = make_convertible<DISPFB>(dispInfo.first);
|
2021-09-01 13:45:00 -04:00
|
|
|
auto dispBounds = GetDisplayBounds(dispInfo.second);
|
2019-12-12 12:44:46 -05:00
|
|
|
|
2021-08-18 19:26:40 -04:00
|
|
|
if(m_present)
|
|
|
|
{
|
|
|
|
m_present->SetPresentationViewport(GetPresentationViewport());
|
2021-09-01 13:45:00 -04:00
|
|
|
m_present->DoPresent(fb.nPSM, fb.GetBufPtr(), fb.GetBufWidth(), dispBounds.first, dispBounds.second);
|
2021-08-18 19:26:40 -04:00
|
|
|
}
|
2019-10-05 10:16:59 -04:00
|
|
|
|
2019-09-12 15:28:40 -04:00
|
|
|
PresentBackbuffer();
|
|
|
|
CGSHandler::FlipImpl();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<VkPhysicalDevice> CGSH_Vulkan::GetPhysicalDevices()
|
|
|
|
{
|
|
|
|
auto result = VK_SUCCESS;
|
|
|
|
|
|
|
|
uint32_t physicalDeviceCount = 0;
|
2019-09-12 17:17:10 -04:00
|
|
|
result = m_instance.vkEnumeratePhysicalDevices(m_instance, &physicalDeviceCount, nullptr);
|
|
|
|
CHECKVULKANERROR(result);
|
2019-12-13 23:21:59 -05:00
|
|
|
|
2019-09-12 15:28:40 -04:00
|
|
|
std::vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount);
|
2019-09-12 17:17:10 -04:00
|
|
|
result = m_instance.vkEnumeratePhysicalDevices(m_instance, &physicalDeviceCount, physicalDevices.data());
|
|
|
|
CHECKVULKANERROR(result);
|
2019-12-13 23:21:59 -05:00
|
|
|
|
2019-09-12 15:28:40 -04:00
|
|
|
return physicalDevices;
|
|
|
|
}
|
|
|
|
|
2020-04-28 13:26:23 -04:00
|
|
|
uint32 CGSH_Vulkan::GetPhysicalDeviceIndex(const std::vector<VkPhysicalDevice>& physicalDevices) const
|
|
|
|
{
|
|
|
|
auto selectedDevice = CDeviceInfo::GetInstance().GetSelectedDevice();
|
|
|
|
for(uint32 i = 0; i < physicalDevices.size(); i++)
|
|
|
|
{
|
|
|
|
const auto& physicalDevice = physicalDevices[i];
|
|
|
|
VkPhysicalDeviceProperties physicalDeviceProperties = {};
|
|
|
|
m_instance.vkGetPhysicalDeviceProperties(physicalDevice, &physicalDeviceProperties);
|
|
|
|
if(
|
2020-04-29 09:18:41 -04:00
|
|
|
(physicalDeviceProperties.deviceID == selectedDevice.deviceId) &&
|
|
|
|
(physicalDeviceProperties.vendorID == selectedDevice.vendorId))
|
2020-04-28 13:26:23 -04:00
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert(false);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-09-12 17:17:10 -04:00
|
|
|
std::vector<uint32_t> CGSH_Vulkan::GetRenderQueueFamilies(VkPhysicalDevice physicalDevice)
|
2019-09-12 15:28:40 -04:00
|
|
|
{
|
|
|
|
auto result = VK_SUCCESS;
|
2019-09-12 17:17:10 -04:00
|
|
|
std::vector<uint32_t> renderQueueFamilies;
|
2019-12-13 23:21:59 -05:00
|
|
|
|
2019-09-12 17:17:10 -04:00
|
|
|
uint32_t queueFamilyCount = 0;
|
|
|
|
m_instance.vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, nullptr);
|
2019-12-13 23:21:59 -05:00
|
|
|
|
2019-09-12 17:17:10 -04:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Found %d queue families.\r\n", queueFamilyCount);
|
2019-12-13 23:21:59 -05:00
|
|
|
|
2019-09-12 17:17:10 -04:00
|
|
|
std::vector<VkQueueFamilyProperties> queueFamilyPropertiesArray(queueFamilyCount);
|
|
|
|
m_instance.vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilyPropertiesArray.data());
|
2019-12-13 23:21:59 -05:00
|
|
|
|
2019-09-12 17:17:10 -04:00
|
|
|
for(uint32_t queueFamilyIndex = 0; queueFamilyIndex < queueFamilyCount; queueFamilyIndex++)
|
|
|
|
{
|
|
|
|
bool graphicsSupported = false;
|
2019-12-13 23:21:59 -05:00
|
|
|
|
2019-09-12 17:17:10 -04:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Queue Family Info:\r\n");
|
|
|
|
|
|
|
|
const auto& queueFamilyProperties = queueFamilyPropertiesArray[queueFamilyIndex];
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Queue Count: %d\r\n", queueFamilyProperties.queueCount);
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Operating modes:\r\n");
|
|
|
|
if(queueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT)
|
|
|
|
{
|
|
|
|
graphicsSupported = true;
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, " Graphics\r\n");
|
|
|
|
}
|
|
|
|
if(queueFamilyProperties.queueFlags & VK_QUEUE_COMPUTE_BIT)
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, " Compute\r\n");
|
|
|
|
}
|
|
|
|
if(queueFamilyProperties.queueFlags & VK_QUEUE_TRANSFER_BIT)
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, " Transfer\r\n");
|
|
|
|
}
|
|
|
|
if(queueFamilyProperties.queueFlags & VK_QUEUE_SPARSE_BINDING_BIT)
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, " Sparse Binding\r\n");
|
|
|
|
}
|
2019-12-13 23:21:59 -05:00
|
|
|
|
2019-09-12 17:17:10 -04:00
|
|
|
VkBool32 surfaceSupported = VK_FALSE;
|
2021-08-18 19:26:40 -04:00
|
|
|
if(m_context->surface)
|
|
|
|
{
|
|
|
|
result = m_instance.vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, m_context->surface, &surfaceSupported);
|
|
|
|
CHECKVULKANERROR(result);
|
2019-12-13 23:21:59 -05:00
|
|
|
|
2021-08-18 19:26:40 -04:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Supports surface: %d\r\n", surfaceSupported);
|
|
|
|
}
|
2019-12-13 23:21:59 -05:00
|
|
|
|
2021-08-18 19:26:40 -04:00
|
|
|
if(graphicsSupported && (!m_context->surface || surfaceSupported))
|
2019-09-12 17:17:10 -04:00
|
|
|
{
|
|
|
|
renderQueueFamilies.push_back(queueFamilyIndex);
|
|
|
|
}
|
|
|
|
}
|
2019-12-13 23:21:59 -05:00
|
|
|
|
2019-09-12 17:17:10 -04:00
|
|
|
return renderQueueFamilies;
|
|
|
|
}
|
|
|
|
|
2019-09-15 10:56:53 -04:00
|
|
|
std::vector<VkSurfaceFormatKHR> CGSH_Vulkan::GetDeviceSurfaceFormats(VkPhysicalDevice physicalDevice)
|
|
|
|
{
|
2019-09-21 18:41:41 -04:00
|
|
|
assert(m_context->surface != VK_NULL_HANDLE);
|
2019-09-15 10:56:53 -04:00
|
|
|
|
|
|
|
auto result = VK_SUCCESS;
|
2019-12-13 23:21:59 -05:00
|
|
|
|
2019-09-15 10:56:53 -04:00
|
|
|
uint32_t surfaceFormatCount = 0;
|
2019-09-21 18:41:41 -04:00
|
|
|
result = m_instance.vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, m_context->surface, &surfaceFormatCount, nullptr);
|
2019-09-15 10:56:53 -04:00
|
|
|
CHECKVULKANERROR(result);
|
2019-12-13 23:21:59 -05:00
|
|
|
|
2019-09-15 10:56:53 -04:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Found %d surface formats.\r\n", surfaceFormatCount);
|
|
|
|
|
|
|
|
std::vector<VkSurfaceFormatKHR> surfaceFormats(surfaceFormatCount);
|
2019-09-21 18:41:41 -04:00
|
|
|
result = m_instance.vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, m_context->surface, &surfaceFormatCount, surfaceFormats.data());
|
2019-09-15 10:56:53 -04:00
|
|
|
CHECKVULKANERROR(result);
|
2019-12-13 23:21:59 -05:00
|
|
|
|
2019-09-15 10:56:53 -04:00
|
|
|
for(const auto& surfaceFormat : surfaceFormats)
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Surface Format Info:\r\n");
|
2019-12-13 23:21:59 -05:00
|
|
|
|
2019-09-15 10:56:53 -04:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Format: %d\r\n", surfaceFormat.format);
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Color Space: %d\r\n", surfaceFormat.colorSpace);
|
|
|
|
}
|
2019-12-13 23:21:59 -05:00
|
|
|
|
2019-09-15 10:56:53 -04:00
|
|
|
return surfaceFormats;
|
|
|
|
}
|
|
|
|
|
2019-09-12 17:17:10 -04:00
|
|
|
void CGSH_Vulkan::CreateDevice(VkPhysicalDevice physicalDevice)
|
|
|
|
{
|
2019-09-21 18:41:41 -04:00
|
|
|
assert(m_context->device.IsEmpty());
|
2019-09-12 15:28:40 -04:00
|
|
|
|
2019-12-13 23:21:59 -05:00
|
|
|
float queuePriorities[] = {1.0f};
|
|
|
|
|
2019-09-15 12:45:04 -04:00
|
|
|
auto deviceQueueCreateInfo = Framework::Vulkan::DeviceQueueCreateInfo();
|
2019-12-13 23:21:59 -05:00
|
|
|
deviceQueueCreateInfo.flags = 0;
|
2019-09-12 15:28:40 -04:00
|
|
|
deviceQueueCreateInfo.queueFamilyIndex = 0;
|
2019-12-13 23:21:59 -05:00
|
|
|
deviceQueueCreateInfo.queueCount = 1;
|
2019-09-12 15:28:40 -04:00
|
|
|
deviceQueueCreateInfo.pQueuePriorities = queuePriorities;
|
|
|
|
|
|
|
|
std::vector<const char*> enabledExtensions;
|
|
|
|
enabledExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
2021-09-24 21:59:21 -04:00
|
|
|
#if GSH_VULKAN_IS_DESKTOP
|
|
|
|
enabledExtensions.push_back(VK_EXT_FRAGMENT_SHADER_INTERLOCK_EXTENSION_NAME);
|
|
|
|
#endif
|
2021-09-25 10:31:27 -04:00
|
|
|
|
2019-09-12 15:28:40 -04:00
|
|
|
std::vector<const char*> enabledLayers;
|
2019-10-08 22:16:55 -04:00
|
|
|
|
2021-09-22 19:23:45 -04:00
|
|
|
Framework::Vulkan::CStructChain createDeviceStructs;
|
2019-10-08 22:16:55 -04:00
|
|
|
|
2021-09-24 21:59:21 -04:00
|
|
|
#if GSH_VULKAN_IS_DESKTOP
|
2021-09-22 19:23:45 -04:00
|
|
|
{
|
|
|
|
auto physicalDeviceFeaturesInvocationInterlock = Framework::Vulkan::PhysicalDeviceFragmentShaderInterlockFeaturesEXT();
|
|
|
|
physicalDeviceFeaturesInvocationInterlock.fragmentShaderPixelInterlock = VK_TRUE;
|
|
|
|
createDeviceStructs.AddStruct(physicalDeviceFeaturesInvocationInterlock);
|
|
|
|
}
|
2021-09-24 21:59:21 -04:00
|
|
|
#endif
|
2021-09-25 10:31:27 -04:00
|
|
|
|
2021-09-22 19:23:45 -04:00
|
|
|
{
|
|
|
|
auto physicalDeviceFeatures2 = Framework::Vulkan::PhysicalDeviceFeatures2KHR();
|
2021-06-24 07:51:50 -04:00
|
|
|
#ifndef __APPLE__
|
2021-09-22 19:23:45 -04:00
|
|
|
//MoltenVK doesn't report this properly (probably due to mobile devices supporting buffer stores and not image stores)
|
|
|
|
physicalDeviceFeatures2.features.fragmentStoresAndAtomics = VK_TRUE;
|
2021-06-24 07:51:50 -04:00
|
|
|
#endif
|
2021-09-24 21:59:21 -04:00
|
|
|
#if GSH_VULKAN_IS_DESKTOP
|
2021-09-22 19:23:45 -04:00
|
|
|
physicalDeviceFeatures2.features.shaderInt16 = VK_TRUE;
|
2021-09-24 21:59:21 -04:00
|
|
|
#endif
|
2021-09-22 19:23:45 -04:00
|
|
|
createDeviceStructs.AddStruct(physicalDeviceFeatures2);
|
|
|
|
}
|
2021-03-23 12:24:30 +00:00
|
|
|
|
2021-09-24 21:59:21 -04:00
|
|
|
#if GSH_VULKAN_IS_DESKTOP
|
2021-09-22 19:23:45 -04:00
|
|
|
{
|
|
|
|
auto physicalDeviceVulkan12Features = Framework::Vulkan::PhysicalDeviceVulkan12Features();
|
|
|
|
physicalDeviceVulkan12Features.shaderInt8 = VK_TRUE;
|
|
|
|
physicalDeviceVulkan12Features.storageBuffer8BitAccess = VK_TRUE;
|
|
|
|
physicalDeviceVulkan12Features.uniformAndStorageBuffer8BitAccess = VK_TRUE;
|
|
|
|
createDeviceStructs.AddStruct(physicalDeviceVulkan12Features);
|
|
|
|
}
|
2021-03-23 12:24:30 +00:00
|
|
|
|
2021-09-22 19:23:45 -04:00
|
|
|
{
|
|
|
|
auto physicalDevice16BitStorageFeatures = Framework::Vulkan::PhysicalDevice16BitStorageFeatures();
|
|
|
|
physicalDevice16BitStorageFeatures.storageBuffer16BitAccess = VK_TRUE;
|
|
|
|
physicalDevice16BitStorageFeatures.uniformAndStorageBuffer16BitAccess = VK_TRUE;
|
|
|
|
createDeviceStructs.AddStruct(physicalDevice16BitStorageFeatures);
|
|
|
|
}
|
2021-09-24 21:59:21 -04:00
|
|
|
#endif
|
2021-09-25 10:31:27 -04:00
|
|
|
|
2019-09-15 12:45:04 -04:00
|
|
|
auto deviceCreateInfo = Framework::Vulkan::DeviceCreateInfo();
|
2021-09-22 19:23:45 -04:00
|
|
|
deviceCreateInfo.pNext = createDeviceStructs.GetNext();
|
2019-12-13 23:21:59 -05:00
|
|
|
deviceCreateInfo.flags = 0;
|
2019-12-24 16:27:14 -05:00
|
|
|
deviceCreateInfo.enabledLayerCount = static_cast<uint32>(enabledLayers.size());
|
2019-12-13 23:21:59 -05:00
|
|
|
deviceCreateInfo.ppEnabledLayerNames = enabledLayers.data();
|
2019-12-24 16:27:14 -05:00
|
|
|
deviceCreateInfo.enabledExtensionCount = static_cast<uint32>(enabledExtensions.size());
|
2019-09-12 15:28:40 -04:00
|
|
|
deviceCreateInfo.ppEnabledExtensionNames = enabledExtensions.data();
|
2019-12-13 23:21:59 -05:00
|
|
|
deviceCreateInfo.queueCreateInfoCount = 1;
|
|
|
|
deviceCreateInfo.pQueueCreateInfos = &deviceQueueCreateInfo;
|
|
|
|
|
2019-09-21 18:41:41 -04:00
|
|
|
m_context->device = Framework::Vulkan::CDevice(m_instance, physicalDevice, deviceCreateInfo);
|
2021-09-29 16:47:42 -04:00
|
|
|
|
|
|
|
{
|
|
|
|
VkPhysicalDeviceProperties deviceProperties = {};
|
|
|
|
m_context->instance->vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties);
|
|
|
|
m_context->storageBufferAlignment = deviceProperties.limits.minStorageBufferOffsetAlignment;
|
2021-09-29 18:42:47 -04:00
|
|
|
m_context->computeWorkgroupInvocations = deviceProperties.limits.maxComputeWorkGroupInvocations;
|
2021-09-29 16:47:42 -04:00
|
|
|
}
|
2019-09-18 13:35:20 -04:00
|
|
|
}
|
|
|
|
|
2019-09-24 12:35:31 -04:00
|
|
|
void CGSH_Vulkan::CreateDescriptorPool()
|
|
|
|
{
|
2019-11-06 20:10:56 -05:00
|
|
|
std::vector<VkDescriptorPoolSize> poolSizes;
|
|
|
|
|
|
|
|
{
|
|
|
|
VkDescriptorPoolSize poolSize = {};
|
2019-12-13 23:21:59 -05:00
|
|
|
poolSize.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
|
2019-11-06 20:10:56 -05:00
|
|
|
poolSize.descriptorCount = 0x800;
|
|
|
|
poolSizes.push_back(poolSize);
|
|
|
|
}
|
2019-12-13 23:21:59 -05:00
|
|
|
|
2019-11-06 20:10:56 -05:00
|
|
|
{
|
|
|
|
VkDescriptorPoolSize poolSize = {};
|
2019-12-13 23:21:59 -05:00
|
|
|
poolSize.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
|
2019-11-15 13:20:14 -05:00
|
|
|
poolSize.descriptorCount = 0x800;
|
|
|
|
poolSizes.push_back(poolSize);
|
|
|
|
}
|
|
|
|
|
2021-06-28 16:36:07 -04:00
|
|
|
{
|
|
|
|
VkDescriptorPoolSize poolSize = {};
|
|
|
|
poolSize.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
|
|
|
|
poolSize.descriptorCount = 0x800;
|
|
|
|
poolSizes.push_back(poolSize);
|
|
|
|
}
|
|
|
|
|
2019-11-15 13:20:14 -05:00
|
|
|
{
|
|
|
|
VkDescriptorPoolSize poolSize = {};
|
2019-12-13 23:21:59 -05:00
|
|
|
poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
2019-11-15 13:20:14 -05:00
|
|
|
poolSize.descriptorCount = 0x800;
|
2019-11-06 20:10:56 -05:00
|
|
|
poolSizes.push_back(poolSize);
|
|
|
|
}
|
|
|
|
|
2021-06-27 09:55:07 -04:00
|
|
|
{
|
|
|
|
VkDescriptorPoolSize poolSize = {};
|
|
|
|
poolSize.type = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
|
|
|
|
poolSize.descriptorCount = 0x800;
|
|
|
|
poolSizes.push_back(poolSize);
|
|
|
|
}
|
|
|
|
|
2019-09-24 12:35:31 -04:00
|
|
|
auto descriptorPoolCreateInfo = Framework::Vulkan::DescriptorPoolCreateInfo();
|
2019-12-24 16:27:14 -05:00
|
|
|
descriptorPoolCreateInfo.poolSizeCount = static_cast<uint32>(poolSizes.size());
|
2019-12-13 23:21:59 -05:00
|
|
|
descriptorPoolCreateInfo.pPoolSizes = poolSizes.data();
|
|
|
|
descriptorPoolCreateInfo.maxSets = 0x1000;
|
|
|
|
|
2019-09-24 12:35:31 -04:00
|
|
|
auto result = m_context->device.vkCreateDescriptorPool(m_context->device, &descriptorPoolCreateInfo, nullptr, &m_context->descriptorPool);
|
|
|
|
CHECKVULKANERROR(result);
|
|
|
|
}
|
|
|
|
|
2019-12-17 19:22:27 -05:00
|
|
|
void CGSH_Vulkan::CreateMemoryBuffer()
|
2019-09-25 19:42:24 -04:00
|
|
|
{
|
2019-12-17 19:22:27 -05:00
|
|
|
assert(m_context->memoryBuffer.IsEmpty());
|
2021-03-30 13:50:52 -04:00
|
|
|
assert(!m_memoryCache);
|
2019-09-25 19:42:24 -04:00
|
|
|
|
2019-12-17 19:22:27 -05:00
|
|
|
m_context->memoryBuffer = Framework::Vulkan::CBuffer(m_context->device,
|
2021-03-29 17:04:29 -04:00
|
|
|
m_context->physicalDeviceMemoryProperties,
|
2021-03-30 13:50:52 -04:00
|
|
|
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
|
|
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
2021-03-29 17:04:29 -04:00
|
|
|
RAMSIZE);
|
2019-09-25 19:42:24 -04:00
|
|
|
|
2021-03-30 13:50:52 -04:00
|
|
|
m_memoryCache = new uint8[RAMSIZE];
|
|
|
|
memset(m_memoryCache, 0, RAMSIZE);
|
2020-01-18 15:39:23 -05:00
|
|
|
|
2021-03-30 13:50:52 -04:00
|
|
|
m_context->memoryBuffer.Write(m_context->queue, m_context->commandBufferPool,
|
|
|
|
m_context->physicalDeviceMemoryProperties, m_memoryCache);
|
2021-04-12 11:42:42 -04:00
|
|
|
|
|
|
|
m_context->memoryBufferCopy = Framework::Vulkan::CBuffer(m_context->device,
|
|
|
|
m_context->physicalDeviceMemoryProperties,
|
|
|
|
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
|
|
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
|
|
|
RAMSIZE);
|
2019-09-25 19:42:24 -04:00
|
|
|
}
|
|
|
|
|
2020-02-17 13:21:50 -05:00
|
|
|
void CGSH_Vulkan::CreateClutBuffer()
|
2019-12-03 13:17:57 -05:00
|
|
|
{
|
2020-02-17 13:21:50 -05:00
|
|
|
assert(m_context->clutBuffer.IsEmpty());
|
2019-12-03 13:17:57 -05:00
|
|
|
|
2020-02-18 13:06:13 -05:00
|
|
|
static const uint32 clutBufferSize = CLUTENTRYCOUNT * sizeof(uint32) * CLUT_CACHE_SIZE;
|
2020-02-17 13:21:50 -05:00
|
|
|
m_context->clutBuffer = Framework::Vulkan::CBuffer(m_context->device,
|
2021-03-29 17:04:29 -04:00
|
|
|
m_context->physicalDeviceMemoryProperties,
|
|
|
|
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT,
|
|
|
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
|
|
|
clutBufferSize);
|
2019-12-06 09:22:01 -05:00
|
|
|
}
|
|
|
|
|
2019-10-01 12:31:49 -04:00
|
|
|
void CGSH_Vulkan::VertexKick(uint8 registerId, uint64 data)
|
|
|
|
{
|
|
|
|
if(m_vtxCount == 0) return;
|
|
|
|
|
|
|
|
bool drawingKick = (registerId == GS_REG_XYZ2) || (registerId == GS_REG_XYZF2);
|
|
|
|
bool fog = (registerId == GS_REG_XYZF2) || (registerId == GS_REG_XYZF3);
|
|
|
|
|
|
|
|
if(!m_drawEnabled) drawingKick = false;
|
|
|
|
|
|
|
|
if(fog)
|
|
|
|
{
|
|
|
|
m_vtxBuffer[m_vtxCount - 1].position = data & 0x00FFFFFFFFFFFFFFULL;
|
|
|
|
m_vtxBuffer[m_vtxCount - 1].rgbaq = m_nReg[GS_REG_RGBAQ];
|
|
|
|
m_vtxBuffer[m_vtxCount - 1].uv = m_nReg[GS_REG_UV];
|
|
|
|
m_vtxBuffer[m_vtxCount - 1].st = m_nReg[GS_REG_ST];
|
|
|
|
m_vtxBuffer[m_vtxCount - 1].fog = static_cast<uint8>(data >> 56);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_vtxBuffer[m_vtxCount - 1].position = data;
|
|
|
|
m_vtxBuffer[m_vtxCount - 1].rgbaq = m_nReg[GS_REG_RGBAQ];
|
|
|
|
m_vtxBuffer[m_vtxCount - 1].uv = m_nReg[GS_REG_UV];
|
|
|
|
m_vtxBuffer[m_vtxCount - 1].st = m_nReg[GS_REG_ST];
|
|
|
|
m_vtxBuffer[m_vtxCount - 1].fog = static_cast<uint8>(m_nReg[GS_REG_FOG] >> 56);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_vtxCount--;
|
|
|
|
|
|
|
|
if(m_vtxCount == 0)
|
|
|
|
{
|
|
|
|
if((m_nReg[GS_REG_PRMODECONT] & 1) != 0)
|
|
|
|
{
|
|
|
|
m_primitiveMode <<= m_nReg[GS_REG_PRIM];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_primitiveMode <<= m_nReg[GS_REG_PRMODE];
|
|
|
|
}
|
|
|
|
|
|
|
|
if(drawingKick)
|
|
|
|
{
|
|
|
|
SetRenderingContext(m_primitiveMode);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(m_primitiveType)
|
|
|
|
{
|
|
|
|
case PRIM_POINT:
|
2021-07-14 14:07:46 -04:00
|
|
|
if(drawingKick) Prim_Point();
|
|
|
|
m_vtxCount = 1;
|
2019-10-01 12:31:49 -04:00
|
|
|
break;
|
|
|
|
case PRIM_LINE:
|
2020-09-18 17:14:24 -04:00
|
|
|
if(drawingKick) Prim_Line();
|
|
|
|
m_vtxCount = 2;
|
2019-10-01 12:31:49 -04:00
|
|
|
break;
|
|
|
|
case PRIM_LINESTRIP:
|
2020-09-18 17:14:24 -04:00
|
|
|
if(drawingKick) Prim_Line();
|
|
|
|
memcpy(&m_vtxBuffer[1], &m_vtxBuffer[0], sizeof(VERTEX));
|
|
|
|
m_vtxCount = 1;
|
2019-10-01 12:31:49 -04:00
|
|
|
break;
|
|
|
|
case PRIM_TRIANGLE:
|
|
|
|
if(drawingKick) Prim_Triangle();
|
|
|
|
m_vtxCount = 3;
|
|
|
|
break;
|
|
|
|
case PRIM_TRIANGLESTRIP:
|
|
|
|
if(drawingKick) Prim_Triangle();
|
|
|
|
memcpy(&m_vtxBuffer[2], &m_vtxBuffer[1], sizeof(VERTEX));
|
|
|
|
memcpy(&m_vtxBuffer[1], &m_vtxBuffer[0], sizeof(VERTEX));
|
|
|
|
m_vtxCount = 1;
|
|
|
|
break;
|
|
|
|
case PRIM_TRIANGLEFAN:
|
|
|
|
if(drawingKick) Prim_Triangle();
|
|
|
|
memcpy(&m_vtxBuffer[1], &m_vtxBuffer[0], sizeof(VERTEX));
|
|
|
|
m_vtxCount = 1;
|
|
|
|
break;
|
|
|
|
case PRIM_SPRITE:
|
2019-11-16 11:43:44 -05:00
|
|
|
if(drawingKick) Prim_Sprite();
|
|
|
|
m_vtxCount = 2;
|
2019-10-01 12:31:49 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGSH_Vulkan::SetRenderingContext(uint64 primReg)
|
|
|
|
{
|
|
|
|
auto prim = make_convertible<PRMODE>(primReg);
|
|
|
|
|
|
|
|
unsigned int context = prim.nContext;
|
|
|
|
|
2019-11-21 13:16:48 -05:00
|
|
|
auto offset = make_convertible<XYOFFSET>(m_nReg[GS_REG_XYOFFSET_1 + context]);
|
2019-11-16 11:27:23 -05:00
|
|
|
auto frame = make_convertible<FRAME>(m_nReg[GS_REG_FRAME_1 + context]);
|
2019-12-22 16:34:47 -05:00
|
|
|
auto zbuf = make_convertible<ZBUF>(m_nReg[GS_REG_ZBUF_1 + context]);
|
2019-11-21 13:16:48 -05:00
|
|
|
auto tex0 = make_convertible<TEX0>(m_nReg[GS_REG_TEX0_1 + context]);
|
2020-05-27 20:07:13 -04:00
|
|
|
auto tex1 = make_convertible<TEX1>(m_nReg[GS_REG_TEX1_1 + context]);
|
2020-01-20 12:53:09 -05:00
|
|
|
auto clamp = make_convertible<CLAMP>(m_nReg[GS_REG_CLAMP_1 + context]);
|
2019-12-12 12:59:17 -05:00
|
|
|
auto alpha = make_convertible<ALPHA>(m_nReg[GS_REG_ALPHA_1 + context]);
|
2019-12-12 13:24:06 -05:00
|
|
|
auto scissor = make_convertible<SCISSOR>(m_nReg[GS_REG_SCISSOR_1 + context]);
|
2019-12-24 16:27:55 -05:00
|
|
|
auto test = make_convertible<TEST>(m_nReg[GS_REG_TEST_1 + context]);
|
2020-01-14 13:25:09 -05:00
|
|
|
auto texA = make_convertible<TEXA>(m_nReg[GS_REG_TEXA]);
|
2020-02-02 11:33:34 -05:00
|
|
|
auto fogCol = make_convertible<FOGCOL>(m_nReg[GS_REG_FOGCOL]);
|
2021-03-23 19:05:24 -04:00
|
|
|
auto scanMask = m_nReg[GS_REG_SCANMSK] & 3;
|
2021-08-06 11:16:04 -04:00
|
|
|
auto colClamp = m_nReg[GS_REG_COLCLAMP] & 1;
|
2021-08-09 12:48:40 -04:00
|
|
|
auto fba = m_nReg[GS_REG_FBA_1 + context] & 1;
|
2019-11-21 13:16:48 -05:00
|
|
|
|
|
|
|
auto pipelineCaps = make_convertible<CDraw::PIPELINE_CAPS>(0);
|
|
|
|
pipelineCaps.hasTexture = prim.nTexture;
|
2020-01-06 19:20:21 -05:00
|
|
|
pipelineCaps.textureHasAlpha = tex0.nColorComp;
|
2020-01-14 13:25:09 -05:00
|
|
|
pipelineCaps.textureBlackIsTransparent = texA.nAEM;
|
2020-01-06 19:20:21 -05:00
|
|
|
pipelineCaps.textureFunction = tex0.nFunction;
|
2020-01-20 12:53:09 -05:00
|
|
|
pipelineCaps.texClampU = clamp.nWMS;
|
|
|
|
pipelineCaps.texClampV = clamp.nWMT;
|
2020-02-02 11:33:34 -05:00
|
|
|
pipelineCaps.hasFog = prim.nFog;
|
2021-03-23 19:05:24 -04:00
|
|
|
pipelineCaps.scanMask = scanMask;
|
2021-08-31 16:40:26 -04:00
|
|
|
pipelineCaps.hasAlphaBlending = prim.nAlpha && m_alphaBlendingEnabled;
|
2021-08-06 11:16:04 -04:00
|
|
|
pipelineCaps.colClamp = colClamp;
|
2021-08-09 12:48:40 -04:00
|
|
|
pipelineCaps.fba = fba;
|
2020-02-13 17:47:05 -05:00
|
|
|
pipelineCaps.hasDstAlphaTest = test.nDestAlphaEnabled;
|
|
|
|
pipelineCaps.dstAlphaTestRef = test.nDestAlphaMode;
|
2019-12-22 16:34:47 -05:00
|
|
|
pipelineCaps.writeDepth = (zbuf.nMask == 0);
|
2019-11-28 20:17:10 -05:00
|
|
|
pipelineCaps.textureFormat = tex0.nPsm;
|
2019-12-15 12:25:31 -05:00
|
|
|
pipelineCaps.clutFormat = tex0.nCPSM;
|
2019-12-15 12:18:44 -05:00
|
|
|
pipelineCaps.framebufferFormat = frame.nPsm;
|
2019-12-22 16:34:47 -05:00
|
|
|
pipelineCaps.depthbufferFormat = zbuf.nPsm | 0x30;
|
2019-11-21 13:16:48 -05:00
|
|
|
|
2020-09-18 17:14:24 -04:00
|
|
|
switch(m_primitiveType)
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
assert(false);
|
2021-07-14 14:07:46 -04:00
|
|
|
[[fallthrough]];
|
2020-09-18 17:14:24 -04:00
|
|
|
case PRIM_TRIANGLE:
|
|
|
|
case PRIM_TRIANGLEFAN:
|
|
|
|
case PRIM_TRIANGLESTRIP:
|
|
|
|
case PRIM_SPRITE:
|
|
|
|
pipelineCaps.primitiveType = CDraw::PIPELINE_PRIMITIVE_TRIANGLE;
|
|
|
|
break;
|
|
|
|
case PRIM_LINE:
|
|
|
|
case PRIM_LINESTRIP:
|
|
|
|
pipelineCaps.primitiveType = CDraw::PIPELINE_PRIMITIVE_LINE;
|
|
|
|
break;
|
2021-07-14 14:07:46 -04:00
|
|
|
case PRIM_POINT:
|
|
|
|
pipelineCaps.primitiveType = CDraw::PIPELINE_PRIMITIVE_POINT;
|
|
|
|
break;
|
2020-09-18 17:14:24 -04:00
|
|
|
}
|
|
|
|
|
2020-01-26 08:56:38 -05:00
|
|
|
uint32 fbWriteMask = ~frame.nMask;
|
|
|
|
|
2020-05-27 20:07:13 -04:00
|
|
|
if(prim.nTexture)
|
|
|
|
{
|
|
|
|
bool minLinear = false;
|
|
|
|
bool magLinear = false;
|
|
|
|
|
|
|
|
switch(tex1.nMinFilter)
|
|
|
|
{
|
|
|
|
case MIN_FILTER_NEAREST:
|
|
|
|
case MIN_FILTER_NEAREST_MIP_NEAREST:
|
|
|
|
case MIN_FILTER_NEAREST_MIP_LINEAR:
|
|
|
|
minLinear = false;
|
|
|
|
break;
|
|
|
|
case MIN_FILTER_LINEAR:
|
|
|
|
case MIN_FILTER_LINEAR_MIP_NEAREST:
|
|
|
|
case MIN_FILTER_LINEAR_MIP_LINEAR:
|
|
|
|
minLinear = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(tex1.nMagFilter)
|
|
|
|
{
|
|
|
|
case MAG_FILTER_NEAREST:
|
|
|
|
magLinear = false;
|
|
|
|
break;
|
|
|
|
case MAG_FILTER_LINEAR:
|
|
|
|
magLinear = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pipelineCaps.textureUseLinearFiltering = (minLinear && magLinear);
|
|
|
|
}
|
|
|
|
|
2019-12-12 12:59:17 -05:00
|
|
|
if(prim.nAlpha)
|
|
|
|
{
|
|
|
|
pipelineCaps.alphaA = alpha.nA;
|
|
|
|
pipelineCaps.alphaB = alpha.nB;
|
|
|
|
pipelineCaps.alphaC = alpha.nC;
|
|
|
|
pipelineCaps.alphaD = alpha.nD;
|
|
|
|
}
|
|
|
|
|
2019-12-24 16:27:55 -05:00
|
|
|
pipelineCaps.depthTestFunction = test.nDepthMethod;
|
2021-08-31 16:40:26 -04:00
|
|
|
if(!test.nDepthEnabled || !m_depthTestingEnabled)
|
2019-12-24 16:27:55 -05:00
|
|
|
{
|
|
|
|
pipelineCaps.depthTestFunction = CGSHandler::DEPTH_TEST_ALWAYS;
|
|
|
|
}
|
|
|
|
|
2020-01-06 17:59:50 -05:00
|
|
|
pipelineCaps.alphaTestFunction = test.nAlphaMethod;
|
|
|
|
pipelineCaps.alphaTestFailAction = test.nAlphaFail;
|
2021-08-31 16:40:26 -04:00
|
|
|
if(!test.nAlphaEnabled || !m_alphaTestingEnabled)
|
2020-01-06 17:59:50 -05:00
|
|
|
{
|
|
|
|
pipelineCaps.alphaTestFunction = CGSHandler::ALPHA_TEST_ALWAYS;
|
|
|
|
}
|
|
|
|
|
2020-01-26 08:56:38 -05:00
|
|
|
//Convert alpha testing to write masking if possible
|
2020-01-06 17:59:50 -05:00
|
|
|
if(
|
2020-01-31 09:34:48 -05:00
|
|
|
(pipelineCaps.alphaTestFunction == CGSHandler::ALPHA_TEST_NEVER) &&
|
|
|
|
(pipelineCaps.alphaTestFailAction == CGSHandler::ALPHA_TEST_FAIL_FBONLY))
|
2020-01-06 17:59:50 -05:00
|
|
|
{
|
|
|
|
pipelineCaps.alphaTestFunction = CGSHandler::ALPHA_TEST_ALWAYS;
|
|
|
|
pipelineCaps.writeDepth = 0;
|
|
|
|
}
|
|
|
|
|
2020-01-26 08:56:38 -05:00
|
|
|
if(
|
2020-01-31 09:34:48 -05:00
|
|
|
(pipelineCaps.alphaTestFunction == CGSHandler::ALPHA_TEST_NEVER) &&
|
|
|
|
(pipelineCaps.alphaTestFailAction == CGSHandler::ALPHA_TEST_FAIL_RGBONLY))
|
2020-01-26 08:56:38 -05:00
|
|
|
{
|
|
|
|
pipelineCaps.alphaTestFunction = CGSHandler::ALPHA_TEST_ALWAYS;
|
|
|
|
pipelineCaps.writeDepth = 0;
|
|
|
|
fbWriteMask &= 0x00FFFFFF;
|
|
|
|
}
|
|
|
|
|
2020-01-08 12:52:17 -05:00
|
|
|
switch(frame.nPsm)
|
|
|
|
{
|
|
|
|
case CGSHandler::PSMCT32:
|
2020-01-11 23:16:39 -05:00
|
|
|
pipelineCaps.maskColor = (fbWriteMask != 0xFFFFFFFF);
|
2020-01-08 12:52:17 -05:00
|
|
|
break;
|
2020-01-21 12:56:18 -05:00
|
|
|
case CGSHandler::PSMCT24:
|
2020-05-19 07:46:26 -04:00
|
|
|
case CGSHandler::PSMZ24:
|
2020-01-26 08:56:38 -05:00
|
|
|
fbWriteMask = fbWriteMask & 0x00FFFFFF;
|
2020-01-21 12:56:18 -05:00
|
|
|
pipelineCaps.maskColor = (fbWriteMask != 0x00FFFFFF);
|
|
|
|
break;
|
2020-01-08 12:52:17 -05:00
|
|
|
case CGSHandler::PSMCT16:
|
|
|
|
case CGSHandler::PSMCT16S:
|
2020-01-26 08:56:38 -05:00
|
|
|
fbWriteMask = RGBA32ToRGBA16(fbWriteMask) & 0xFFFF;
|
2020-01-11 23:16:39 -05:00
|
|
|
pipelineCaps.maskColor = (fbWriteMask != 0xFFFF);
|
2020-01-08 12:52:17 -05:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2021-04-12 15:39:33 -04:00
|
|
|
//Check if we need to save a copy of RAM because primitive writes to texture area
|
2021-04-12 11:42:42 -04:00
|
|
|
bool needsTextureCopy = false;
|
2021-04-12 15:39:33 -04:00
|
|
|
uint32 memoryCopyAddress = 0;
|
|
|
|
uint32 memoryCopySize = 0;
|
2021-04-12 11:42:42 -04:00
|
|
|
if((m_primitiveType == PRIM_SPRITE) && pipelineCaps.hasTexture)
|
|
|
|
{
|
2021-04-12 15:39:33 -04:00
|
|
|
uint32 texBufPtr = tex0.GetBufPtr();
|
|
|
|
uint32 frameBufPtr = frame.GetBasePtr();
|
|
|
|
uint32 depthBufPtr = zbuf.GetBasePtr();
|
|
|
|
bool isTexUpperBytePsm = CGsPixelFormats::IsPsmUpperByte(tex0.nPsm);
|
|
|
|
{
|
|
|
|
bool isFrame24Bits = CGsPixelFormats::IsPsm24Bits(frame.nPsm);
|
|
|
|
needsTextureCopy |= (texBufPtr == frameBufPtr) && !(isTexUpperBytePsm && isFrame24Bits);
|
|
|
|
}
|
2021-04-12 11:42:42 -04:00
|
|
|
if(pipelineCaps.writeDepth)
|
|
|
|
{
|
2021-04-12 15:39:33 -04:00
|
|
|
bool isDepth24Bits = CGsPixelFormats::IsPsm24Bits(zbuf.nPsm);
|
|
|
|
needsTextureCopy |= (texBufPtr == depthBufPtr) && !(isTexUpperBytePsm && isDepth24Bits);
|
|
|
|
}
|
|
|
|
if(needsTextureCopy)
|
|
|
|
{
|
|
|
|
CGsCachedArea textureArea;
|
|
|
|
textureArea.SetArea(tex0.nPsm, tex0.nBufPtr, tex0.GetBufWidth(), tex0.GetHeight());
|
|
|
|
memoryCopyAddress = texBufPtr;
|
|
|
|
memoryCopySize = textureArea.GetSize();
|
2021-04-26 10:29:59 -04:00
|
|
|
if((memoryCopyAddress + memoryCopySize) > RAMSIZE)
|
|
|
|
{
|
|
|
|
//Some games (Castlevania: Curse of Darkness) have a texture that goes beyond
|
|
|
|
//RAMSIZE, make sure we stay inside bounds.
|
|
|
|
memoryCopySize = RAMSIZE - memoryCopyAddress;
|
|
|
|
}
|
2021-04-12 15:39:33 -04:00
|
|
|
m_draw->SetMemoryCopyParams(memoryCopyAddress, memoryCopySize);
|
2021-04-12 11:42:42 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pipelineCaps.textureUseMemoryCopy = needsTextureCopy;
|
|
|
|
|
2019-11-21 13:16:48 -05:00
|
|
|
m_draw->SetPipelineCaps(pipelineCaps);
|
2020-01-08 12:52:17 -05:00
|
|
|
m_draw->SetFramebufferParams(frame.GetBasePtr(), frame.GetWidth(), fbWriteMask);
|
2019-12-22 16:34:47 -05:00
|
|
|
m_draw->SetDepthbufferParams(zbuf.GetBasePtr(), frame.GetWidth());
|
2019-12-13 23:21:59 -05:00
|
|
|
m_draw->SetTextureParams(tex0.GetBufPtr(), tex0.GetBufWidth(),
|
2020-01-09 13:06:41 -05:00
|
|
|
tex0.GetWidth(), tex0.GetHeight(), tex0.nCSA * 0x10);
|
2020-01-14 13:25:09 -05:00
|
|
|
m_draw->SetTextureAlphaParams(texA.nTA0, texA.nTA1);
|
2020-01-20 12:53:09 -05:00
|
|
|
m_draw->SetTextureClampParams(
|
2020-01-31 09:34:48 -05:00
|
|
|
clamp.GetMinU(), clamp.GetMinV(),
|
|
|
|
clamp.GetMaxU(), clamp.GetMaxV());
|
2020-02-02 11:33:34 -05:00
|
|
|
m_draw->SetFogParams(
|
2020-02-04 09:29:13 -05:00
|
|
|
static_cast<float>(fogCol.nFCR) / 255.f,
|
|
|
|
static_cast<float>(fogCol.nFCG) / 255.f,
|
|
|
|
static_cast<float>(fogCol.nFCB) / 255.f);
|
2020-01-08 12:51:47 -05:00
|
|
|
m_draw->SetAlphaBlendingParams(alpha.nFix);
|
2020-01-22 20:34:07 -05:00
|
|
|
m_draw->SetAlphaTestParams(test.nAlphaRef);
|
2019-12-12 13:24:06 -05:00
|
|
|
m_draw->SetScissor(scissor.scax0, scissor.scay0,
|
2019-12-13 23:21:59 -05:00
|
|
|
scissor.scax1 - scissor.scax0 + 1,
|
|
|
|
scissor.scay1 - scissor.scay0 + 1);
|
2019-11-16 11:27:23 -05:00
|
|
|
|
2019-10-01 12:31:49 -04:00
|
|
|
m_primOfsX = offset.GetX();
|
|
|
|
m_primOfsY = offset.GetY();
|
2019-11-21 13:16:48 -05:00
|
|
|
|
|
|
|
m_texWidth = tex0.GetWidth();
|
|
|
|
m_texHeight = tex0.GetHeight();
|
2019-10-01 12:31:49 -04:00
|
|
|
}
|
|
|
|
|
2021-07-14 14:07:46 -04:00
|
|
|
void CGSH_Vulkan::Prim_Point()
|
|
|
|
{
|
|
|
|
auto xyz = make_convertible<XYZ>(m_vtxBuffer[0].position);
|
|
|
|
auto rgbaq = make_convertible<RGBAQ>(m_vtxBuffer[0].rgbaq);
|
|
|
|
|
|
|
|
float x = xyz.GetX();
|
|
|
|
float y = xyz.GetY();
|
|
|
|
uint32 z = xyz.nZ;
|
|
|
|
|
|
|
|
x -= m_primOfsX;
|
|
|
|
y -= m_primOfsY;
|
|
|
|
|
|
|
|
auto color = MakeColor(
|
|
|
|
rgbaq.nR, rgbaq.nG,
|
|
|
|
rgbaq.nB, rgbaq.nA);
|
|
|
|
|
|
|
|
// clang-format off
|
|
|
|
CDraw::PRIM_VERTEX vertex =
|
|
|
|
{
|
|
|
|
//x, y, z, color, s, t, q, f
|
|
|
|
x, y, z, color, 0, 0, 1, 0,
|
|
|
|
};
|
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
m_draw->AddVertices(&vertex, &vertex + 1);
|
|
|
|
}
|
|
|
|
|
2020-09-18 17:14:24 -04:00
|
|
|
void CGSH_Vulkan::Prim_Line()
|
|
|
|
{
|
|
|
|
XYZ pos[2];
|
|
|
|
pos[0] <<= m_vtxBuffer[1].position;
|
|
|
|
pos[1] <<= m_vtxBuffer[0].position;
|
|
|
|
|
|
|
|
float x1 = pos[0].GetX(), x2 = pos[1].GetX();
|
|
|
|
float y1 = pos[0].GetY(), y2 = pos[1].GetY();
|
|
|
|
uint32 z1 = pos[0].nZ, z2 = pos[1].nZ;
|
|
|
|
|
|
|
|
RGBAQ rgbaq[2];
|
|
|
|
rgbaq[0] <<= m_vtxBuffer[1].rgbaq;
|
|
|
|
rgbaq[1] <<= m_vtxBuffer[0].rgbaq;
|
|
|
|
|
|
|
|
x1 -= m_primOfsX;
|
|
|
|
x2 -= m_primOfsX;
|
|
|
|
|
|
|
|
y1 -= m_primOfsY;
|
|
|
|
y2 -= m_primOfsY;
|
|
|
|
|
|
|
|
float s[2] = {0, 0};
|
|
|
|
float t[2] = {0, 0};
|
|
|
|
float q[2] = {1, 1};
|
|
|
|
|
2020-09-18 17:50:52 -04:00
|
|
|
if(m_primitiveMode.nTexture)
|
|
|
|
{
|
|
|
|
if(m_primitiveMode.nUseUV)
|
|
|
|
{
|
|
|
|
UV uv[3];
|
|
|
|
uv[0] <<= m_vtxBuffer[1].uv;
|
|
|
|
uv[1] <<= m_vtxBuffer[0].uv;
|
|
|
|
|
|
|
|
s[0] = uv[0].GetU() / static_cast<float>(m_texWidth);
|
|
|
|
s[1] = uv[1].GetU() / static_cast<float>(m_texWidth);
|
|
|
|
|
|
|
|
t[0] = uv[0].GetV() / static_cast<float>(m_texHeight);
|
|
|
|
t[1] = uv[1].GetV() / static_cast<float>(m_texHeight);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-03-20 14:42:50 -04:00
|
|
|
ST st[2];
|
|
|
|
st[0] <<= m_vtxBuffer[1].st;
|
|
|
|
st[1] <<= m_vtxBuffer[0].st;
|
|
|
|
|
|
|
|
s[0] = st[0].nS;
|
|
|
|
s[1] = st[1].nS;
|
|
|
|
t[0] = st[0].nT;
|
|
|
|
t[1] = st[1].nT;
|
|
|
|
|
|
|
|
q[0] = rgbaq[0].nQ;
|
|
|
|
q[1] = rgbaq[1].nQ;
|
2020-09-18 17:50:52 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-18 17:14:24 -04:00
|
|
|
auto color1 = MakeColor(
|
|
|
|
rgbaq[0].nR, rgbaq[0].nG,
|
|
|
|
rgbaq[0].nB, rgbaq[0].nA);
|
|
|
|
|
|
|
|
auto color2 = MakeColor(
|
|
|
|
rgbaq[1].nR, rgbaq[1].nG,
|
|
|
|
rgbaq[1].nB, rgbaq[1].nA);
|
|
|
|
|
|
|
|
// clang-format off
|
|
|
|
CDraw::PRIM_VERTEX vertices[] =
|
|
|
|
{
|
|
|
|
{ x1, y1, z1, color1, s[0], t[0], q[0], 0 },
|
|
|
|
{ x2, y2, z2, color2, s[1], t[1], q[1], 0 },
|
|
|
|
};
|
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
m_draw->AddVertices(std::begin(vertices), std::end(vertices));
|
|
|
|
}
|
|
|
|
|
2019-10-01 12:31:49 -04:00
|
|
|
void CGSH_Vulkan::Prim_Triangle()
|
|
|
|
{
|
2019-11-16 11:43:44 -05:00
|
|
|
XYZ pos[3];
|
|
|
|
pos[0] <<= m_vtxBuffer[2].position;
|
|
|
|
pos[1] <<= m_vtxBuffer[1].position;
|
|
|
|
pos[2] <<= m_vtxBuffer[0].position;
|
2019-10-01 12:31:49 -04:00
|
|
|
|
2019-11-16 11:43:44 -05:00
|
|
|
float x1 = pos[0].GetX(), x2 = pos[1].GetX(), x3 = pos[2].GetX();
|
|
|
|
float y1 = pos[0].GetY(), y2 = pos[1].GetY(), y3 = pos[2].GetY();
|
2019-12-13 23:21:59 -05:00
|
|
|
uint32 z1 = pos[0].nZ, z2 = pos[1].nZ, z3 = pos[2].nZ;
|
2019-10-01 12:31:49 -04:00
|
|
|
|
|
|
|
RGBAQ rgbaq[3];
|
|
|
|
rgbaq[0] <<= m_vtxBuffer[2].rgbaq;
|
|
|
|
rgbaq[1] <<= m_vtxBuffer[1].rgbaq;
|
|
|
|
rgbaq[2] <<= m_vtxBuffer[0].rgbaq;
|
|
|
|
|
|
|
|
x1 -= m_primOfsX;
|
|
|
|
x2 -= m_primOfsX;
|
|
|
|
x3 -= m_primOfsX;
|
|
|
|
|
|
|
|
y1 -= m_primOfsY;
|
|
|
|
y2 -= m_primOfsY;
|
|
|
|
y3 -= m_primOfsY;
|
|
|
|
|
2019-11-21 13:16:48 -05:00
|
|
|
float s[3] = {0, 0, 0};
|
|
|
|
float t[3] = {0, 0, 0};
|
|
|
|
float q[3] = {1, 1, 1};
|
|
|
|
|
2020-02-02 11:33:34 -05:00
|
|
|
float f[3] = {0, 0, 0};
|
|
|
|
|
|
|
|
if(m_primitiveMode.nFog)
|
|
|
|
{
|
|
|
|
f[0] = static_cast<float>(0xFF - m_vtxBuffer[2].fog) / 255.0f;
|
|
|
|
f[1] = static_cast<float>(0xFF - m_vtxBuffer[1].fog) / 255.0f;
|
|
|
|
f[2] = static_cast<float>(0xFF - m_vtxBuffer[0].fog) / 255.0f;
|
|
|
|
}
|
|
|
|
|
2019-11-21 13:16:48 -05:00
|
|
|
if(m_primitiveMode.nTexture)
|
|
|
|
{
|
|
|
|
if(m_primitiveMode.nUseUV)
|
|
|
|
{
|
|
|
|
UV uv[3];
|
|
|
|
uv[0] <<= m_vtxBuffer[2].uv;
|
|
|
|
uv[1] <<= m_vtxBuffer[1].uv;
|
|
|
|
uv[2] <<= m_vtxBuffer[0].uv;
|
|
|
|
|
|
|
|
s[0] = uv[0].GetU() / static_cast<float>(m_texWidth);
|
|
|
|
s[1] = uv[1].GetU() / static_cast<float>(m_texWidth);
|
|
|
|
s[2] = uv[2].GetU() / static_cast<float>(m_texWidth);
|
|
|
|
|
|
|
|
t[0] = uv[0].GetV() / static_cast<float>(m_texHeight);
|
|
|
|
t[1] = uv[1].GetV() / static_cast<float>(m_texHeight);
|
|
|
|
t[2] = uv[2].GetV() / static_cast<float>(m_texHeight);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ST st[3];
|
|
|
|
st[0] <<= m_vtxBuffer[2].st;
|
|
|
|
st[1] <<= m_vtxBuffer[1].st;
|
|
|
|
st[2] <<= m_vtxBuffer[0].st;
|
|
|
|
|
|
|
|
s[0] = st[0].nS;
|
|
|
|
s[1] = st[1].nS;
|
|
|
|
s[2] = st[2].nS;
|
|
|
|
t[0] = st[0].nT;
|
|
|
|
t[1] = st[1].nT;
|
|
|
|
t[2] = st[2].nT;
|
|
|
|
|
|
|
|
q[0] = rgbaq[0].nQ;
|
|
|
|
q[1] = rgbaq[1].nQ;
|
|
|
|
q[2] = rgbaq[2].nQ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-01 12:31:49 -04:00
|
|
|
auto color1 = MakeColor(
|
|
|
|
rgbaq[0].nR, rgbaq[0].nG,
|
|
|
|
rgbaq[0].nB, rgbaq[0].nA);
|
|
|
|
|
|
|
|
auto color2 = MakeColor(
|
|
|
|
rgbaq[1].nR, rgbaq[1].nG,
|
|
|
|
rgbaq[1].nB, rgbaq[1].nA);
|
|
|
|
|
|
|
|
auto color3 = MakeColor(
|
|
|
|
rgbaq[2].nR, rgbaq[2].nG,
|
|
|
|
rgbaq[2].nB, rgbaq[2].nA);
|
|
|
|
|
|
|
|
if(m_primitiveMode.nShading == 0)
|
|
|
|
{
|
|
|
|
//Flat shaded triangles use the last color set
|
|
|
|
color1 = color2 = color3;
|
|
|
|
}
|
|
|
|
|
|
|
|
// clang-format off
|
|
|
|
CDraw::PRIM_VERTEX vertices[] =
|
|
|
|
{
|
2020-02-02 11:33:34 -05:00
|
|
|
{ x1, y1, z1, color1, s[0], t[0], q[0], f[0]},
|
|
|
|
{ x2, y2, z2, color2, s[1], t[1], q[1], f[1]},
|
|
|
|
{ x3, y3, z3, color3, s[2], t[2], q[2], f[2]},
|
2019-10-01 12:31:49 -04:00
|
|
|
};
|
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
m_draw->AddVertices(std::begin(vertices), std::end(vertices));
|
|
|
|
}
|
|
|
|
|
2019-11-16 11:43:44 -05:00
|
|
|
void CGSH_Vulkan::Prim_Sprite()
|
|
|
|
{
|
|
|
|
XYZ pos[2];
|
|
|
|
pos[0] <<= m_vtxBuffer[1].position;
|
|
|
|
pos[1] <<= m_vtxBuffer[0].position;
|
|
|
|
|
|
|
|
float x1 = pos[0].GetX(), y1 = pos[0].GetY();
|
|
|
|
float x2 = pos[1].GetX(), y2 = pos[1].GetY();
|
|
|
|
uint32 z = pos[1].nZ;
|
|
|
|
|
|
|
|
RGBAQ rgbaq[2];
|
|
|
|
rgbaq[0] <<= m_vtxBuffer[1].rgbaq;
|
|
|
|
rgbaq[1] <<= m_vtxBuffer[0].rgbaq;
|
|
|
|
|
|
|
|
x1 -= m_primOfsX;
|
|
|
|
x2 -= m_primOfsX;
|
|
|
|
|
|
|
|
y1 -= m_primOfsY;
|
|
|
|
y2 -= m_primOfsY;
|
|
|
|
|
2019-11-21 13:16:48 -05:00
|
|
|
float s[2] = {0, 0};
|
|
|
|
float t[2] = {0, 0};
|
|
|
|
|
|
|
|
if(m_primitiveMode.nTexture)
|
|
|
|
{
|
|
|
|
if(m_primitiveMode.nUseUV)
|
|
|
|
{
|
|
|
|
UV uv[2];
|
|
|
|
uv[0] <<= m_vtxBuffer[1].uv;
|
|
|
|
uv[1] <<= m_vtxBuffer[0].uv;
|
|
|
|
|
|
|
|
s[0] = uv[0].GetU() / static_cast<float>(m_texWidth);
|
|
|
|
s[1] = uv[1].GetU() / static_cast<float>(m_texWidth);
|
|
|
|
|
|
|
|
t[0] = uv[0].GetV() / static_cast<float>(m_texHeight);
|
|
|
|
t[1] = uv[1].GetV() / static_cast<float>(m_texHeight);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ST st[2];
|
|
|
|
|
|
|
|
st[0] <<= m_vtxBuffer[1].st;
|
|
|
|
st[1] <<= m_vtxBuffer[0].st;
|
|
|
|
|
2020-01-25 09:09:10 -05:00
|
|
|
float q1 = rgbaq[1].nQ;
|
|
|
|
float q2 = rgbaq[0].nQ;
|
|
|
|
if(q1 == 0) q1 = 1;
|
|
|
|
if(q2 == 0) q2 = 1;
|
2019-11-21 13:16:48 -05:00
|
|
|
|
2020-01-25 09:09:10 -05:00
|
|
|
s[0] = st[0].nS / q1;
|
|
|
|
s[1] = st[1].nS / q2;
|
|
|
|
|
|
|
|
t[0] = st[0].nT / q1;
|
|
|
|
t[1] = st[1].nT / q2;
|
2019-11-21 13:16:48 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-16 11:43:44 -05:00
|
|
|
auto color = MakeColor(
|
|
|
|
rgbaq[1].nR, rgbaq[1].nG,
|
|
|
|
rgbaq[1].nB, rgbaq[1].nA);
|
|
|
|
|
|
|
|
// clang-format off
|
|
|
|
CDraw::PRIM_VERTEX vertices[] =
|
|
|
|
{
|
2020-02-02 11:33:34 -05:00
|
|
|
{x1, y1, z, color, s[0], t[0], 1, 0},
|
|
|
|
{x2, y1, z, color, s[1], t[0], 1, 0},
|
|
|
|
{x1, y2, z, color, s[0], t[1], 1, 0},
|
2019-11-16 11:43:44 -05:00
|
|
|
|
2020-02-02 11:33:34 -05:00
|
|
|
{x1, y2, z, color, s[0], t[1], 1, 0},
|
|
|
|
{x2, y1, z, color, s[1], t[0], 1, 0},
|
|
|
|
{x2, y2, z, color, s[1], t[1], 1, 0},
|
2019-11-16 11:43:44 -05:00
|
|
|
};
|
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
m_draw->AddVertices(std::begin(vertices), std::end(vertices));
|
|
|
|
}
|
|
|
|
|
2020-02-18 13:06:13 -05:00
|
|
|
int32 CGSH_Vulkan::FindCachedClut(const CLUTKEY& key) const
|
|
|
|
{
|
|
|
|
for(uint32 i = 0; i < CLUT_CACHE_SIZE; i++)
|
|
|
|
{
|
|
|
|
if(m_clutStates[i] == key)
|
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
CGSH_Vulkan::CLUTKEY CGSH_Vulkan::MakeCachedClutKey(const TEX0& tex0, const TEXCLUT& texClut)
|
|
|
|
{
|
|
|
|
auto clutKey = make_convertible<CLUTKEY>(0);
|
|
|
|
clutKey.idx4 = CGsPixelFormats::IsPsmIDTEX4(tex0.nPsm);
|
|
|
|
clutKey.cbp = tex0.nCBP;
|
|
|
|
clutKey.cpsm = tex0.nCPSM;
|
|
|
|
clutKey.csm = tex0.nCSM;
|
|
|
|
clutKey.csa = tex0.nCSA;
|
|
|
|
clutKey.cbw = texClut.nCBW;
|
|
|
|
clutKey.cou = texClut.nCOU;
|
|
|
|
clutKey.cov = texClut.nCOV;
|
|
|
|
return clutKey;
|
|
|
|
}
|
|
|
|
|
2019-09-12 15:28:40 -04:00
|
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
// Other Functions
|
|
|
|
/////////////////////////////////////////////////////////////
|
|
|
|
|
2019-10-01 12:31:49 -04:00
|
|
|
void CGSH_Vulkan::WriteRegisterImpl(uint8 registerId, uint64 data)
|
|
|
|
{
|
2020-07-25 14:31:44 -04:00
|
|
|
//Some games such as Silent Hill 2 don't finish their transfers
|
|
|
|
//completely: make sure we push the data to the GS's RAM nevertheless.
|
2021-08-20 17:36:29 -04:00
|
|
|
if(!m_xferBuffer.empty() && (registerId != GS_REG_HWREG))
|
2020-07-25 14:31:44 -04:00
|
|
|
{
|
|
|
|
ProcessHostToLocalTransfer();
|
|
|
|
}
|
|
|
|
|
2019-10-01 12:31:49 -04:00
|
|
|
CGSHandler::WriteRegisterImpl(registerId, data);
|
|
|
|
|
|
|
|
switch(registerId)
|
|
|
|
{
|
|
|
|
case GS_REG_PRIM:
|
|
|
|
{
|
|
|
|
unsigned int newPrimitiveType = static_cast<unsigned int>(data & 0x07);
|
|
|
|
if(newPrimitiveType != m_primitiveType)
|
|
|
|
{
|
|
|
|
m_draw->FlushVertices();
|
|
|
|
}
|
|
|
|
m_primitiveType = newPrimitiveType;
|
|
|
|
switch(m_primitiveType)
|
|
|
|
{
|
|
|
|
case PRIM_POINT:
|
|
|
|
m_vtxCount = 1;
|
|
|
|
break;
|
|
|
|
case PRIM_LINE:
|
|
|
|
case PRIM_LINESTRIP:
|
|
|
|
m_vtxCount = 2;
|
|
|
|
break;
|
|
|
|
case PRIM_TRIANGLE:
|
|
|
|
case PRIM_TRIANGLESTRIP:
|
|
|
|
case PRIM_TRIANGLEFAN:
|
|
|
|
m_vtxCount = 3;
|
|
|
|
break;
|
|
|
|
case PRIM_SPRITE:
|
|
|
|
m_vtxCount = 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case GS_REG_XYZ2:
|
|
|
|
case GS_REG_XYZ3:
|
|
|
|
case GS_REG_XYZF2:
|
|
|
|
case GS_REG_XYZF3:
|
|
|
|
VertexKick(registerId, data);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-12 15:28:40 -04:00
|
|
|
void CGSH_Vulkan::ProcessHostToLocalTransfer()
|
|
|
|
{
|
2020-01-18 10:16:17 -05:00
|
|
|
//Flush previous cached info
|
2020-02-18 13:06:13 -05:00
|
|
|
memset(&m_clutStates, 0, sizeof(m_clutStates));
|
2020-01-30 12:58:06 -05:00
|
|
|
m_draw->FlushRenderPass();
|
2020-01-18 10:16:17 -05:00
|
|
|
|
2019-11-13 09:45:15 -05:00
|
|
|
auto bltBuf = make_convertible<BITBLTBUF>(m_nReg[GS_REG_BITBLTBUF]);
|
|
|
|
auto trxReg = make_convertible<TRXREG>(m_nReg[GS_REG_TRXREG]);
|
|
|
|
auto trxPos = make_convertible<TRXPOS>(m_nReg[GS_REG_TRXPOS]);
|
|
|
|
|
2020-02-12 19:41:35 -05:00
|
|
|
m_transferHost->Params.bufAddress = bltBuf.GetDstPtr();
|
|
|
|
m_transferHost->Params.bufWidth = bltBuf.GetDstWidth();
|
|
|
|
m_transferHost->Params.rrw = trxReg.nRRW;
|
|
|
|
m_transferHost->Params.dsax = trxPos.nDSAX;
|
|
|
|
m_transferHost->Params.dsay = trxPos.nDSAY;
|
2019-11-13 09:45:15 -05:00
|
|
|
|
2020-02-12 19:41:35 -05:00
|
|
|
auto pipelineCaps = make_convertible<CTransferHost::PIPELINE_CAPS>(0);
|
2019-11-28 20:17:10 -05:00
|
|
|
pipelineCaps.dstFormat = bltBuf.nDstPsm;
|
|
|
|
|
2020-02-12 19:41:35 -05:00
|
|
|
m_transferHost->SetPipelineCaps(pipelineCaps);
|
|
|
|
m_transferHost->DoTransfer(m_xferBuffer);
|
2020-07-25 14:31:44 -04:00
|
|
|
|
|
|
|
m_xferBuffer.clear();
|
2019-09-12 15:28:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void CGSH_Vulkan::ProcessLocalToHostTransfer()
|
|
|
|
{
|
2021-03-30 13:50:52 -04:00
|
|
|
//Make sure our local RAM copy is in sync with GPU
|
|
|
|
SyncMemoryCache();
|
2019-09-12 15:28:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void CGSH_Vulkan::ProcessLocalToLocalTransfer()
|
|
|
|
{
|
2020-02-12 09:24:59 -05:00
|
|
|
//Flush previous cached info
|
2020-02-18 13:06:13 -05:00
|
|
|
memset(&m_clutStates, 0, sizeof(m_clutStates));
|
2020-02-12 09:24:59 -05:00
|
|
|
m_draw->FlushRenderPass();
|
|
|
|
|
|
|
|
auto bltBuf = make_convertible<BITBLTBUF>(m_nReg[GS_REG_BITBLTBUF]);
|
|
|
|
auto trxReg = make_convertible<TRXREG>(m_nReg[GS_REG_TRXREG]);
|
|
|
|
auto trxPos = make_convertible<TRXPOS>(m_nReg[GS_REG_TRXPOS]);
|
|
|
|
|
2020-02-12 13:04:40 -05:00
|
|
|
assert(trxPos.nDIR == 0);
|
|
|
|
|
2020-02-12 09:24:59 -05:00
|
|
|
m_transferLocal->Params.srcBufAddress = bltBuf.GetSrcPtr();
|
|
|
|
m_transferLocal->Params.srcBufWidth = bltBuf.GetSrcWidth();
|
|
|
|
m_transferLocal->Params.dstBufAddress = bltBuf.GetDstPtr();
|
|
|
|
m_transferLocal->Params.dstBufWidth = bltBuf.GetDstWidth();
|
|
|
|
m_transferLocal->Params.ssax = trxPos.nSSAX;
|
|
|
|
m_transferLocal->Params.ssay = trxPos.nSSAY;
|
|
|
|
m_transferLocal->Params.dsax = trxPos.nDSAX;
|
|
|
|
m_transferLocal->Params.dsay = trxPos.nDSAY;
|
|
|
|
m_transferLocal->Params.rrw = trxReg.nRRW;
|
|
|
|
m_transferLocal->Params.rrh = trxReg.nRRH;
|
|
|
|
|
|
|
|
auto pipelineCaps = make_convertible<CTransferLocal::PIPELINE_CAPS>(0);
|
|
|
|
pipelineCaps.srcFormat = bltBuf.nSrcPsm;
|
|
|
|
pipelineCaps.dstFormat = bltBuf.nDstPsm;
|
|
|
|
|
|
|
|
m_transferLocal->SetPipelineCaps(pipelineCaps);
|
|
|
|
m_transferLocal->DoTransfer();
|
2019-09-12 15:28:40 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void CGSH_Vulkan::ProcessClutTransfer(uint32 csa, uint32)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-12-20 17:28:09 -05:00
|
|
|
void CGSH_Vulkan::BeginTransferWrite()
|
|
|
|
{
|
2020-07-25 14:31:44 -04:00
|
|
|
assert(m_xferBuffer.empty());
|
2019-12-20 17:28:09 -05:00
|
|
|
m_xferBuffer.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGSH_Vulkan::TransferWrite(const uint8* imageData, uint32 length)
|
|
|
|
{
|
|
|
|
m_xferBuffer.insert(m_xferBuffer.end(), imageData, imageData + length);
|
|
|
|
}
|
|
|
|
|
2021-03-30 13:50:52 -04:00
|
|
|
void CGSH_Vulkan::WriteBackMemoryCache()
|
|
|
|
{
|
|
|
|
m_frameCommandBuffer->Flush();
|
|
|
|
m_context->device.vkQueueWaitIdle(m_context->queue);
|
|
|
|
|
|
|
|
m_context->memoryBuffer.Write(m_context->queue, m_context->commandBufferPool,
|
|
|
|
m_context->physicalDeviceMemoryProperties, m_memoryCache);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGSH_Vulkan::SyncMemoryCache()
|
|
|
|
{
|
|
|
|
m_frameCommandBuffer->Flush();
|
|
|
|
m_context->device.vkQueueWaitIdle(m_context->queue);
|
|
|
|
|
|
|
|
m_context->memoryBuffer.Read(m_context->queue, m_context->commandBufferPool,
|
|
|
|
m_context->physicalDeviceMemoryProperties, m_memoryCache);
|
|
|
|
}
|
|
|
|
|
2019-12-06 09:22:37 -05:00
|
|
|
void CGSH_Vulkan::SyncCLUT(const TEX0& tex0)
|
|
|
|
{
|
|
|
|
if(!CGsPixelFormats::IsPsmIDTEX(tex0.nPsm)) return;
|
2020-01-24 17:57:48 -05:00
|
|
|
if(!ProcessCLD(tex0)) return;
|
2020-01-18 10:17:03 -05:00
|
|
|
|
2020-01-28 13:21:56 -05:00
|
|
|
auto texClut = make_convertible<TEXCLUT>(m_nReg[GS_REG_TEXCLUT]);
|
|
|
|
|
2020-02-18 13:06:13 -05:00
|
|
|
auto clutKey = MakeCachedClutKey(tex0, texClut);
|
|
|
|
int32 clutCacheIndex = FindCachedClut(clutKey);
|
|
|
|
if(clutCacheIndex == -1)
|
2020-01-28 13:21:56 -05:00
|
|
|
{
|
2020-02-18 13:06:13 -05:00
|
|
|
clutCacheIndex = m_nextClutCacheIndex++;
|
|
|
|
m_nextClutCacheIndex %= CLUT_CACHE_SIZE;
|
|
|
|
m_clutStates[clutCacheIndex] = clutKey;
|
2020-01-28 13:21:56 -05:00
|
|
|
|
2020-02-18 13:06:13 -05:00
|
|
|
m_draw->FlushRenderPass();
|
|
|
|
uint32 clutBufferOffset = sizeof(uint32) * CLUTENTRYCOUNT * clutCacheIndex;
|
|
|
|
m_clutLoad->DoClutLoad(clutBufferOffset, tex0, texClut);
|
|
|
|
}
|
2019-12-06 09:22:37 -05:00
|
|
|
|
2020-02-18 13:06:13 -05:00
|
|
|
uint32 clutBufferOffset = sizeof(uint32) * CLUTENTRYCOUNT * clutCacheIndex;
|
|
|
|
m_draw->SetClutBufferOffset(clutBufferOffset);
|
2019-12-06 09:22:37 -05:00
|
|
|
}
|
|
|
|
|
2020-01-18 15:39:23 -05:00
|
|
|
uint8* CGSH_Vulkan::GetRam() const
|
|
|
|
{
|
2021-03-30 13:50:52 -04:00
|
|
|
return m_memoryCache;
|
2020-01-18 15:39:23 -05:00
|
|
|
}
|
|
|
|
|
2019-09-12 15:28:40 -04:00
|
|
|
Framework::CBitmap CGSH_Vulkan::GetScreenshot()
|
|
|
|
{
|
|
|
|
return Framework::CBitmap();
|
|
|
|
}
|
2021-08-20 10:37:49 -04:00
|
|
|
|
|
|
|
bool CGSH_Vulkan::GetDepthTestingEnabled() const
|
|
|
|
{
|
|
|
|
return m_depthTestingEnabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGSH_Vulkan::SetDepthTestingEnabled(bool depthTestingEnabled)
|
|
|
|
{
|
|
|
|
m_depthTestingEnabled = depthTestingEnabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CGSH_Vulkan::GetAlphaBlendingEnabled() const
|
|
|
|
{
|
|
|
|
return m_alphaBlendingEnabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGSH_Vulkan::SetAlphaBlendingEnabled(bool alphaBlendingEnabled)
|
|
|
|
{
|
|
|
|
m_alphaBlendingEnabled = alphaBlendingEnabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CGSH_Vulkan::GetAlphaTestingEnabled() const
|
|
|
|
{
|
|
|
|
return m_alphaTestingEnabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGSH_Vulkan::SetAlphaTestingEnabled(bool alphaTestingEnabled)
|
|
|
|
{
|
|
|
|
m_alphaTestingEnabled = alphaTestingEnabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
Framework::CBitmap CGSH_Vulkan::GetFramebuffer(uint64 frameReg)
|
|
|
|
{
|
|
|
|
Framework::CBitmap result;
|
|
|
|
SendGSCall([&]() { result = GetFramebufferImpl(frameReg); }, true);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-08-20 17:17:49 -04:00
|
|
|
Framework::CBitmap CGSH_Vulkan::GetTexture(uint64 tex0Reg, uint32 maxMip, uint64 miptbp1Reg, uint64 miptbp2Reg, uint32 mipLevel)
|
|
|
|
{
|
|
|
|
Framework::CBitmap result;
|
|
|
|
SendGSCall([&]() { result = GetTextureImpl(tex0Reg, maxMip, miptbp1Reg, miptbp2Reg, mipLevel); }, true);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-08-20 11:11:45 -04:00
|
|
|
int CGSH_Vulkan::GetFramebufferScale()
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2021-08-20 17:17:49 -04:00
|
|
|
const CGSHandler::VERTEX* CGSH_Vulkan::GetInputVertices() const
|
|
|
|
{
|
|
|
|
return m_vtxBuffer;
|
|
|
|
}
|
|
|
|
|
2021-08-20 10:37:49 -04:00
|
|
|
Framework::CBitmap CGSH_Vulkan::GetFramebufferImpl(uint64 frameReg)
|
|
|
|
{
|
|
|
|
auto frame = make_convertible<FRAME>(frameReg);
|
|
|
|
|
|
|
|
SyncMemoryCache();
|
|
|
|
|
|
|
|
uint32 frameWidth = frame.GetWidth();
|
|
|
|
uint32 frameHeight = 1024;
|
|
|
|
Framework::CBitmap bitmap;
|
|
|
|
|
|
|
|
switch(frame.nPsm)
|
|
|
|
{
|
|
|
|
case PSMCT32:
|
2021-08-31 17:53:44 -04:00
|
|
|
{
|
|
|
|
bitmap = ReadImage32<CGsPixelFormats::CPixelIndexorPSMCT32>(GetRam(), frame.GetBasePtr(),
|
|
|
|
frame.nWidth, frameWidth, frameHeight);
|
|
|
|
}
|
|
|
|
break;
|
2021-08-20 10:37:49 -04:00
|
|
|
case PSMCT24:
|
|
|
|
{
|
2021-08-31 17:53:44 -04:00
|
|
|
bitmap = ReadImage32<CGsPixelFormats::CPixelIndexorPSMCT32, 0x00FFFFFF>(GetRam(), frame.GetBasePtr(),
|
|
|
|
frame.nWidth, frameWidth, frameHeight);
|
2021-08-20 10:37:49 -04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PSMCT16:
|
|
|
|
{
|
2021-08-20 11:42:29 -04:00
|
|
|
bitmap = ReadImage16<CGsPixelFormats::CPixelIndexorPSMCT16>(GetRam(), frame.GetBasePtr(),
|
|
|
|
frame.nWidth, frameWidth, frameHeight);
|
2021-08-20 10:37:49 -04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PSMCT16S:
|
|
|
|
{
|
2021-08-20 11:42:29 -04:00
|
|
|
bitmap = ReadImage16<CGsPixelFormats::CPixelIndexorPSMCT16S>(GetRam(), frame.GetBasePtr(),
|
|
|
|
frame.nWidth, frameWidth, frameHeight);
|
2021-08-20 10:37:49 -04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return bitmap;
|
|
|
|
}
|
|
|
|
|
2021-08-20 17:17:49 -04:00
|
|
|
Framework::CBitmap CGSH_Vulkan::GetTextureImpl(uint64 tex0Reg, uint32 maxMip, uint64 miptbp1Reg, uint64 miptbp2Reg, uint32 mipLevel)
|
2021-08-20 10:37:49 -04:00
|
|
|
{
|
2021-08-20 17:17:49 -04:00
|
|
|
auto tex0 = make_convertible<TEX0>(tex0Reg);
|
|
|
|
auto width = std::max<uint32>(tex0.GetWidth() >> mipLevel, 1);
|
|
|
|
auto height = std::max<uint32>(tex0.GetHeight() >> mipLevel, 1);
|
2021-08-20 10:37:49 -04:00
|
|
|
|
2021-08-20 17:17:49 -04:00
|
|
|
SyncMemoryCache();
|
|
|
|
|
|
|
|
Framework::CBitmap bitmap;
|
|
|
|
|
|
|
|
switch(tex0.nPsm)
|
|
|
|
{
|
2021-08-31 17:53:44 -04:00
|
|
|
case PSMCT32:
|
|
|
|
{
|
|
|
|
bitmap = ReadImage32<CGsPixelFormats::CPixelIndexorPSMCT32>(GetRam(), tex0.GetBufPtr(),
|
|
|
|
tex0.nBufWidth, tex0.GetWidth(), tex0.GetHeight());
|
|
|
|
}
|
|
|
|
break;
|
2021-08-20 17:17:49 -04:00
|
|
|
case PSMT8:
|
|
|
|
{
|
|
|
|
bitmap = Framework::CBitmap(tex0.GetWidth(), tex0.GetHeight(), 8);
|
|
|
|
auto bitmapPixels = reinterpret_cast<uint8*>(bitmap.GetPixels());
|
|
|
|
CGsPixelFormats::CPixelIndexorPSMT8 indexor(GetRam(), tex0.GetBufPtr(), tex0.nBufWidth);
|
|
|
|
for(unsigned int y = 0; y < height; y++)
|
|
|
|
{
|
|
|
|
for(unsigned int x = 0; x < width; x++)
|
|
|
|
{
|
|
|
|
uint8 pixel = indexor.GetPixel(x, y);
|
|
|
|
(*bitmapPixels) = pixel;
|
|
|
|
bitmapPixels++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return bitmap;
|
2021-08-20 10:37:49 -04:00
|
|
|
}
|