1 #include <cstring>
2 #include "../GsPixelFormats.h"
3 #include "../../Log.h"
4 #include "GSH_Vulkan.h"
5 #include "GSH_VulkanDeviceInfo.h"
6 #include "vulkan/StructDefs.h"
7 #include "vulkan/Utils.h"
8
9 #define LOG_NAME ("gsh_vulkan")
10
11 using namespace GSH_Vulkan;
12
13 //#define FILL_IMAGES
14
MakeColor(uint8 r,uint8 g,uint8 b,uint8 a)15 static uint32 MakeColor(uint8 r, uint8 g, uint8 b, uint8 a)
16 {
17 return (a << 24) | (b << 16) | (g << 8) | (r);
18 }
19
RGBA32ToRGBA16(uint32 inputColor)20 static uint16 RGBA32ToRGBA16(uint32 inputColor)
21 {
22 uint32 result = 0;
23 result |= ((inputColor & 0x000000F8) >> (0 + 3)) << 0;
24 result |= ((inputColor & 0x0000F800) >> (8 + 3)) << 5;
25 result |= ((inputColor & 0x00F80000) >> (16 + 3)) << 10;
26 result |= ((inputColor & 0x80000000) >> 31) << 15;
27 return result;
28 }
29
30 template <typename StorageFormat>
CreateSwizzleTable(Framework::Vulkan::CDevice & device,const VkPhysicalDeviceMemoryProperties & memoryProperties,VkQueue queue,Framework::Vulkan::CCommandBufferPool & commandBufferPool)31 static Framework::Vulkan::CImage CreateSwizzleTable(Framework::Vulkan::CDevice& device,
32 const VkPhysicalDeviceMemoryProperties& memoryProperties, VkQueue queue, Framework::Vulkan::CCommandBufferPool& commandBufferPool)
33 {
34 auto result = Framework::Vulkan::CImage(device, memoryProperties,
35 VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
36 VK_FORMAT_R32_UINT, StorageFormat::PAGEWIDTH, StorageFormat::PAGEHEIGHT);
37 result.Fill(queue, commandBufferPool, memoryProperties,
38 CGsPixelFormats::CPixelIndexor<StorageFormat>::GetPageOffsets());
39 result.SetLayout(queue, commandBufferPool,
40 VK_IMAGE_LAYOUT_GENERAL, VK_ACCESS_SHADER_READ_BIT);
41 return result;
42 }
43
CGSH_Vulkan()44 CGSH_Vulkan::CGSH_Vulkan()
45 {
46 m_context = std::make_shared<CContext>();
47 }
48
CreateInstance(bool useValidationLayers)49 Framework::Vulkan::CInstance CGSH_Vulkan::CreateInstance(bool useValidationLayers)
50 {
51 auto instanceCreateInfo = Framework::Vulkan::InstanceCreateInfo();
52
53 std::vector<const char*> extensions;
54 extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
55 #ifdef _WIN32
56 extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
57 #endif
58 #ifdef __APPLE__
59 extensions.push_back(VK_MVK_MACOS_SURFACE_EXTENSION_NAME);
60 #endif
61 #ifdef __linux__
62 extensions.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME);
63 #endif
64
65 std::vector<const char*> layers;
66 #if defined(_DEBUG) && !defined(__APPLE__)
67 if(useValidationLayers)
68 {
69 layers.push_back("VK_LAYER_KHRONOS_validation");
70 }
71 #endif
72
73 auto appInfo = Framework::Vulkan::ApplicationInfo();
74 appInfo.pApplicationName = "Play!";
75 appInfo.pEngineName = "Play!";
76 appInfo.apiVersion = VK_MAKE_VERSION(1, 1, 0);
77
78 instanceCreateInfo.pApplicationInfo = &appInfo;
79 instanceCreateInfo.enabledExtensionCount = extensions.size();
80 instanceCreateInfo.ppEnabledExtensionNames = extensions.data();
81 instanceCreateInfo.enabledLayerCount = layers.size();
82 instanceCreateInfo.ppEnabledLayerNames = layers.data();
83 return Framework::Vulkan::CInstance(instanceCreateInfo);
84 }
85
InitializeImpl()86 void CGSH_Vulkan::InitializeImpl()
87 {
88 assert(!m_instance.IsEmpty());
89 m_context->instance = &m_instance;
90
91 auto physicalDevices = GetPhysicalDevices();
92 assert(!physicalDevices.empty());
93 auto physicalDeviceIndex = GetPhysicalDeviceIndex(physicalDevices);
94 m_context->physicalDevice = physicalDevices[physicalDeviceIndex];
95
96 auto renderQueueFamilies = GetRenderQueueFamilies(m_context->physicalDevice);
97 assert(!renderQueueFamilies.empty());
98 auto renderQueueFamily = renderQueueFamilies[0];
99
100 m_instance.vkGetPhysicalDeviceMemoryProperties(m_context->physicalDevice, &m_context->physicalDeviceMemoryProperties);
101
102 auto surfaceFormats = GetDeviceSurfaceFormats(m_context->physicalDevice);
103 assert(surfaceFormats.size() > 0);
104 m_context->surfaceFormat = surfaceFormats[0];
105
106 CreateDevice(m_context->physicalDevice);
107 m_context->device.vkGetDeviceQueue(m_context->device, renderQueueFamily, 0, &m_context->queue);
108 m_context->commandBufferPool = Framework::Vulkan::CCommandBufferPool(m_context->device, renderQueueFamily);
109
110 CreateDescriptorPool();
111 CreateMemoryBuffer();
112 CreateClutBuffer();
113
114 m_swizzleTablePSMCT32 = CreateSwizzleTable<CGsPixelFormats::STORAGEPSMCT32>(m_context->device, m_context->physicalDeviceMemoryProperties, m_context->queue, m_context->commandBufferPool);
115 m_swizzleTablePSMCT16 = CreateSwizzleTable<CGsPixelFormats::STORAGEPSMCT16>(m_context->device, m_context->physicalDeviceMemoryProperties, m_context->queue, m_context->commandBufferPool);
116 m_swizzleTablePSMCT16S = CreateSwizzleTable<CGsPixelFormats::STORAGEPSMCT16S>(m_context->device, m_context->physicalDeviceMemoryProperties, m_context->queue, m_context->commandBufferPool);
117 m_swizzleTablePSMT8 = CreateSwizzleTable<CGsPixelFormats::STORAGEPSMT8>(m_context->device, m_context->physicalDeviceMemoryProperties, m_context->queue, m_context->commandBufferPool);
118 m_swizzleTablePSMT4 = CreateSwizzleTable<CGsPixelFormats::STORAGEPSMT4>(m_context->device, m_context->physicalDeviceMemoryProperties, m_context->queue, m_context->commandBufferPool);
119 m_swizzleTablePSMZ32 = CreateSwizzleTable<CGsPixelFormats::STORAGEPSMZ32>(m_context->device, m_context->physicalDeviceMemoryProperties, m_context->queue, m_context->commandBufferPool);
120 m_swizzleTablePSMZ16 = CreateSwizzleTable<CGsPixelFormats::STORAGEPSMZ16>(m_context->device, m_context->physicalDeviceMemoryProperties, m_context->queue, m_context->commandBufferPool);
121
122 m_context->swizzleTablePSMCT32View = m_swizzleTablePSMCT32.CreateImageView();
123 m_context->swizzleTablePSMCT16View = m_swizzleTablePSMCT16.CreateImageView();
124 m_context->swizzleTablePSMCT16SView = m_swizzleTablePSMCT16S.CreateImageView();
125 m_context->swizzleTablePSMT8View = m_swizzleTablePSMT8.CreateImageView();
126 m_context->swizzleTablePSMT4View = m_swizzleTablePSMT4.CreateImageView();
127 m_context->swizzleTablePSMZ32View = m_swizzleTablePSMZ32.CreateImageView();
128 m_context->swizzleTablePSMZ16View = m_swizzleTablePSMZ16.CreateImageView();
129
130 m_frameCommandBuffer = std::make_shared<CFrameCommandBuffer>(m_context);
131 m_clutLoad = std::make_shared<CClutLoad>(m_context, m_frameCommandBuffer);
132 m_draw = std::make_shared<CDraw>(m_context, m_frameCommandBuffer);
133 m_present = std::make_shared<CPresent>(m_context);
134 m_transferHost = std::make_shared<CTransferHost>(m_context, m_frameCommandBuffer);
135 m_transferLocal = std::make_shared<CTransferLocal>(m_context, m_frameCommandBuffer);
136
137 m_frameCommandBuffer->RegisterWriter(m_draw.get());
138 m_frameCommandBuffer->RegisterWriter(m_transferHost.get());
139 m_frameCommandBuffer->BeginFrame();
140 }
141
ReleaseImpl()142 void CGSH_Vulkan::ReleaseImpl()
143 {
144 ResetImpl();
145
146 //Flush any pending rendering commands
147 m_context->device.vkQueueWaitIdle(m_context->queue);
148
149 m_clutLoad.reset();
150 m_draw.reset();
151 m_present.reset();
152 m_transferHost.reset();
153 m_transferLocal.reset();
154 m_frameCommandBuffer.reset();
155
156 m_context->device.vkDestroyImageView(m_context->device, m_context->swizzleTablePSMCT32View, nullptr);
157 m_context->device.vkDestroyImageView(m_context->device, m_context->swizzleTablePSMCT16View, nullptr);
158 m_context->device.vkDestroyImageView(m_context->device, m_context->swizzleTablePSMCT16SView, nullptr);
159 m_context->device.vkDestroyImageView(m_context->device, m_context->swizzleTablePSMT8View, nullptr);
160 m_context->device.vkDestroyImageView(m_context->device, m_context->swizzleTablePSMT4View, nullptr);
161 m_context->device.vkDestroyImageView(m_context->device, m_context->swizzleTablePSMZ32View, nullptr);
162 m_context->device.vkDestroyImageView(m_context->device, m_context->swizzleTablePSMZ16View, nullptr);
163
164 m_swizzleTablePSMCT32.Reset();
165 m_swizzleTablePSMCT16.Reset();
166 m_swizzleTablePSMCT16S.Reset();
167 m_swizzleTablePSMT8.Reset();
168 m_swizzleTablePSMT4.Reset();
169 m_swizzleTablePSMZ32.Reset();
170 m_swizzleTablePSMZ16.Reset();
171
172 m_context->device.vkDestroyDescriptorPool(m_context->device, m_context->descriptorPool, nullptr);
173 m_context->clutBuffer.Reset();
174 m_context->device.vkUnmapMemory(m_context->device, m_context->memoryBuffer.GetMemory());
175 m_context->memoryBuffer.Reset();
176 m_context->commandBufferPool.Reset();
177 m_context->device.Reset();
178 }
179
ResetImpl()180 void CGSH_Vulkan::ResetImpl()
181 {
182 m_vtxCount = 0;
183 m_primitiveType = PRIM_INVALID;
184 memset(&m_clutStates, 0, sizeof(m_clutStates));
185 }
186
SetPresentationParams(const CGSHandler::PRESENTATION_PARAMS & presentationParams)187 void CGSH_Vulkan::SetPresentationParams(const CGSHandler::PRESENTATION_PARAMS& presentationParams)
188 {
189 CGSHandler::SetPresentationParams(presentationParams);
190 m_present->ValidateSwapChain(presentationParams);
191 }
192
MarkNewFrame()193 void CGSH_Vulkan::MarkNewFrame()
194 {
195 m_drawCallCount = m_frameCommandBuffer->GetFlushCount();
196 m_frameCommandBuffer->ResetFlushCount();
197 m_frameCommandBuffer->EndFrame();
198 CGSHandler::MarkNewFrame();
199 m_frameCommandBuffer->BeginFrame();
200 }
201
FlipImpl()202 void CGSH_Vulkan::FlipImpl()
203 {
204 auto dispInfo = GetCurrentDisplayInfo();
205 auto fb = make_convertible<DISPFB>(dispInfo.first);
206 auto d = make_convertible<DISPLAY>(dispInfo.second);
207
208 unsigned int dispWidth = (d.nW + 1) / (d.nMagX + 1);
209 unsigned int dispHeight = (d.nH + 1);
210
211 bool halfHeight = GetCrtIsInterlaced() && GetCrtIsFrameMode();
212 if(halfHeight) dispHeight /= 2;
213
214 m_present->SetPresentationViewport(GetPresentationViewport());
215 m_present->DoPresent(fb.nPSM, fb.GetBufPtr(), fb.GetBufWidth(), dispWidth, dispHeight);
216
217 PresentBackbuffer();
218 CGSHandler::FlipImpl();
219 }
220
GetPhysicalDevices()221 std::vector<VkPhysicalDevice> CGSH_Vulkan::GetPhysicalDevices()
222 {
223 auto result = VK_SUCCESS;
224
225 uint32_t physicalDeviceCount = 0;
226 result = m_instance.vkEnumeratePhysicalDevices(m_instance, &physicalDeviceCount, nullptr);
227 CHECKVULKANERROR(result);
228
229 std::vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount);
230 result = m_instance.vkEnumeratePhysicalDevices(m_instance, &physicalDeviceCount, physicalDevices.data());
231 CHECKVULKANERROR(result);
232
233 return physicalDevices;
234 }
235
GetPhysicalDeviceIndex(const std::vector<VkPhysicalDevice> & physicalDevices) const236 uint32 CGSH_Vulkan::GetPhysicalDeviceIndex(const std::vector<VkPhysicalDevice>& physicalDevices) const
237 {
238 auto selectedDevice = CDeviceInfo::GetInstance().GetSelectedDevice();
239 for(uint32 i = 0; i < physicalDevices.size(); i++)
240 {
241 const auto& physicalDevice = physicalDevices[i];
242 VkPhysicalDeviceProperties physicalDeviceProperties = {};
243 m_instance.vkGetPhysicalDeviceProperties(physicalDevice, &physicalDeviceProperties);
244 if(
245 (physicalDeviceProperties.deviceID == selectedDevice.deviceId) &&
246 (physicalDeviceProperties.vendorID == selectedDevice.vendorId))
247 {
248 return i;
249 }
250 }
251 assert(false);
252 return 0;
253 }
254
GetRenderQueueFamilies(VkPhysicalDevice physicalDevice)255 std::vector<uint32_t> CGSH_Vulkan::GetRenderQueueFamilies(VkPhysicalDevice physicalDevice)
256 {
257 assert(m_context->surface != VK_NULL_HANDLE);
258
259 auto result = VK_SUCCESS;
260 std::vector<uint32_t> renderQueueFamilies;
261
262 uint32_t queueFamilyCount = 0;
263 m_instance.vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, nullptr);
264
265 CLog::GetInstance().Print(LOG_NAME, "Found %d queue families.\r\n", queueFamilyCount);
266
267 std::vector<VkQueueFamilyProperties> queueFamilyPropertiesArray(queueFamilyCount);
268 m_instance.vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilyPropertiesArray.data());
269
270 for(uint32_t queueFamilyIndex = 0; queueFamilyIndex < queueFamilyCount; queueFamilyIndex++)
271 {
272 bool graphicsSupported = false;
273
274 CLog::GetInstance().Print(LOG_NAME, "Queue Family Info:\r\n");
275
276 const auto& queueFamilyProperties = queueFamilyPropertiesArray[queueFamilyIndex];
277 CLog::GetInstance().Print(LOG_NAME, "Queue Count: %d\r\n", queueFamilyProperties.queueCount);
278 CLog::GetInstance().Print(LOG_NAME, "Operating modes:\r\n");
279 if(queueFamilyProperties.queueFlags & VK_QUEUE_GRAPHICS_BIT)
280 {
281 graphicsSupported = true;
282 CLog::GetInstance().Print(LOG_NAME, " Graphics\r\n");
283 }
284 if(queueFamilyProperties.queueFlags & VK_QUEUE_COMPUTE_BIT)
285 {
286 CLog::GetInstance().Print(LOG_NAME, " Compute\r\n");
287 }
288 if(queueFamilyProperties.queueFlags & VK_QUEUE_TRANSFER_BIT)
289 {
290 CLog::GetInstance().Print(LOG_NAME, " Transfer\r\n");
291 }
292 if(queueFamilyProperties.queueFlags & VK_QUEUE_SPARSE_BINDING_BIT)
293 {
294 CLog::GetInstance().Print(LOG_NAME, " Sparse Binding\r\n");
295 }
296
297 VkBool32 surfaceSupported = VK_FALSE;
298 result = m_instance.vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, m_context->surface, &surfaceSupported);
299 CHECKVULKANERROR(result);
300
301 CLog::GetInstance().Print(LOG_NAME, "Supports surface: %d\r\n", surfaceSupported);
302
303 if(graphicsSupported && surfaceSupported)
304 {
305 renderQueueFamilies.push_back(queueFamilyIndex);
306 }
307 }
308
309 return renderQueueFamilies;
310 }
311
GetDeviceSurfaceFormats(VkPhysicalDevice physicalDevice)312 std::vector<VkSurfaceFormatKHR> CGSH_Vulkan::GetDeviceSurfaceFormats(VkPhysicalDevice physicalDevice)
313 {
314 assert(m_context->surface != VK_NULL_HANDLE);
315
316 auto result = VK_SUCCESS;
317
318 uint32_t surfaceFormatCount = 0;
319 result = m_instance.vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, m_context->surface, &surfaceFormatCount, nullptr);
320 CHECKVULKANERROR(result);
321
322 CLog::GetInstance().Print(LOG_NAME, "Found %d surface formats.\r\n", surfaceFormatCount);
323
324 std::vector<VkSurfaceFormatKHR> surfaceFormats(surfaceFormatCount);
325 result = m_instance.vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, m_context->surface, &surfaceFormatCount, surfaceFormats.data());
326 CHECKVULKANERROR(result);
327
328 for(const auto& surfaceFormat : surfaceFormats)
329 {
330 CLog::GetInstance().Print(LOG_NAME, "Surface Format Info:\r\n");
331
332 CLog::GetInstance().Print(LOG_NAME, "Format: %d\r\n", surfaceFormat.format);
333 CLog::GetInstance().Print(LOG_NAME, "Color Space: %d\r\n", surfaceFormat.colorSpace);
334 }
335
336 return surfaceFormats;
337 }
338
CreateDevice(VkPhysicalDevice physicalDevice)339 void CGSH_Vulkan::CreateDevice(VkPhysicalDevice physicalDevice)
340 {
341 assert(m_context->device.IsEmpty());
342
343 float queuePriorities[] = {1.0f};
344
345 auto deviceQueueCreateInfo = Framework::Vulkan::DeviceQueueCreateInfo();
346 deviceQueueCreateInfo.flags = 0;
347 deviceQueueCreateInfo.queueFamilyIndex = 0;
348 deviceQueueCreateInfo.queueCount = 1;
349 deviceQueueCreateInfo.pQueuePriorities = queuePriorities;
350
351 std::vector<const char*> enabledExtensions;
352 enabledExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
353 enabledExtensions.push_back(VK_EXT_FRAGMENT_SHADER_INTERLOCK_EXTENSION_NAME);
354
355 std::vector<const char*> enabledLayers;
356
357 auto physicalDeviceFeaturesInvocationInterlock = Framework::Vulkan::PhysicalDeviceFragmentShaderInterlockFeaturesEXT();
358 physicalDeviceFeaturesInvocationInterlock.fragmentShaderPixelInterlock = VK_TRUE;
359
360 auto physicalDeviceFeatures2 = Framework::Vulkan::PhysicalDeviceFeatures2KHR();
361 physicalDeviceFeatures2.pNext = &physicalDeviceFeaturesInvocationInterlock;
362 physicalDeviceFeatures2.features.fragmentStoresAndAtomics = VK_TRUE;
363
364 auto deviceCreateInfo = Framework::Vulkan::DeviceCreateInfo();
365 deviceCreateInfo.pNext = &physicalDeviceFeatures2;
366 deviceCreateInfo.flags = 0;
367 deviceCreateInfo.enabledLayerCount = static_cast<uint32>(enabledLayers.size());
368 deviceCreateInfo.ppEnabledLayerNames = enabledLayers.data();
369 deviceCreateInfo.enabledExtensionCount = static_cast<uint32>(enabledExtensions.size());
370 deviceCreateInfo.ppEnabledExtensionNames = enabledExtensions.data();
371 deviceCreateInfo.queueCreateInfoCount = 1;
372 deviceCreateInfo.pQueueCreateInfos = &deviceQueueCreateInfo;
373
374 m_context->device = Framework::Vulkan::CDevice(m_instance, physicalDevice, deviceCreateInfo);
375 }
376
CreateDescriptorPool()377 void CGSH_Vulkan::CreateDescriptorPool()
378 {
379 std::vector<VkDescriptorPoolSize> poolSizes;
380
381 {
382 VkDescriptorPoolSize poolSize = {};
383 poolSize.type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
384 poolSize.descriptorCount = 0x800;
385 poolSizes.push_back(poolSize);
386 }
387
388 {
389 VkDescriptorPoolSize poolSize = {};
390 poolSize.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
391 poolSize.descriptorCount = 0x800;
392 poolSizes.push_back(poolSize);
393 }
394
395 {
396 VkDescriptorPoolSize poolSize = {};
397 poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
398 poolSize.descriptorCount = 0x800;
399 poolSizes.push_back(poolSize);
400 }
401
402 auto descriptorPoolCreateInfo = Framework::Vulkan::DescriptorPoolCreateInfo();
403 descriptorPoolCreateInfo.poolSizeCount = static_cast<uint32>(poolSizes.size());
404 descriptorPoolCreateInfo.pPoolSizes = poolSizes.data();
405 descriptorPoolCreateInfo.maxSets = 0x1000;
406
407 auto result = m_context->device.vkCreateDescriptorPool(m_context->device, &descriptorPoolCreateInfo, nullptr, &m_context->descriptorPool);
408 CHECKVULKANERROR(result);
409 }
410
CreateMemoryBuffer()411 void CGSH_Vulkan::CreateMemoryBuffer()
412 {
413 assert(m_context->memoryBuffer.IsEmpty());
414
415 m_context->memoryBuffer = Framework::Vulkan::CBuffer(m_context->device,
416 m_context->physicalDeviceMemoryProperties, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, RAMSIZE);
417
418 #ifdef FILL_IMAGES
419 {
420 uint32* memory = nullptr;
421 m_context->device.vkMapMemory(m_context->device, m_context->memoryBuffer.GetMemory(),
422 0, VK_WHOLE_SIZE, 0, reinterpret_cast<void**>(&memory));
423 memset(memory, 0x80, RAMSIZE);
424 m_context->device.vkUnmapMemory(m_context->device, m_context->memoryBuffer.GetMemory());
425 }
426 #endif
427
428 auto result = m_context->device.vkMapMemory(m_context->device, m_context->memoryBuffer.GetMemory(),
429 0, VK_WHOLE_SIZE, 0, reinterpret_cast<void**>(&m_memoryBufferPtr));
430 CHECKVULKANERROR(result);
431 }
432
CreateClutBuffer()433 void CGSH_Vulkan::CreateClutBuffer()
434 {
435 assert(m_context->clutBuffer.IsEmpty());
436
437 static const uint32 clutBufferSize = CLUTENTRYCOUNT * sizeof(uint32) * CLUT_CACHE_SIZE;
438 m_context->clutBuffer = Framework::Vulkan::CBuffer(m_context->device,
439 m_context->physicalDeviceMemoryProperties, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, clutBufferSize);
440
441 #ifdef FILL_IMAGES
442 {
443 uint32* memory = nullptr;
444 m_context->device.vkMapMemory(m_context->device, m_context->clutBuffer.GetMemory(),
445 0, VK_WHOLE_SIZE, 0, reinterpret_cast<void**>(&memory));
446 memset(memory, 0x80, clutBufferSize);
447 m_context->device.vkUnmapMemory(m_context->device, m_context->clutBuffer.GetMemory());
448 }
449 #endif
450 }
451
VertexKick(uint8 registerId,uint64 data)452 void CGSH_Vulkan::VertexKick(uint8 registerId, uint64 data)
453 {
454 if(m_vtxCount == 0) return;
455
456 bool drawingKick = (registerId == GS_REG_XYZ2) || (registerId == GS_REG_XYZF2);
457 bool fog = (registerId == GS_REG_XYZF2) || (registerId == GS_REG_XYZF3);
458
459 if(!m_drawEnabled) drawingKick = false;
460
461 if(fog)
462 {
463 m_vtxBuffer[m_vtxCount - 1].position = data & 0x00FFFFFFFFFFFFFFULL;
464 m_vtxBuffer[m_vtxCount - 1].rgbaq = m_nReg[GS_REG_RGBAQ];
465 m_vtxBuffer[m_vtxCount - 1].uv = m_nReg[GS_REG_UV];
466 m_vtxBuffer[m_vtxCount - 1].st = m_nReg[GS_REG_ST];
467 m_vtxBuffer[m_vtxCount - 1].fog = static_cast<uint8>(data >> 56);
468 }
469 else
470 {
471 m_vtxBuffer[m_vtxCount - 1].position = data;
472 m_vtxBuffer[m_vtxCount - 1].rgbaq = m_nReg[GS_REG_RGBAQ];
473 m_vtxBuffer[m_vtxCount - 1].uv = m_nReg[GS_REG_UV];
474 m_vtxBuffer[m_vtxCount - 1].st = m_nReg[GS_REG_ST];
475 m_vtxBuffer[m_vtxCount - 1].fog = static_cast<uint8>(m_nReg[GS_REG_FOG] >> 56);
476 }
477
478 m_vtxCount--;
479
480 if(m_vtxCount == 0)
481 {
482 if((m_nReg[GS_REG_PRMODECONT] & 1) != 0)
483 {
484 m_primitiveMode <<= m_nReg[GS_REG_PRIM];
485 }
486 else
487 {
488 m_primitiveMode <<= m_nReg[GS_REG_PRMODE];
489 }
490
491 if(drawingKick)
492 {
493 SetRenderingContext(m_primitiveMode);
494 }
495
496 switch(m_primitiveType)
497 {
498 #if 0
499 case PRIM_POINT:
500 if(nDrawingKick) Prim_Point();
501 m_nVtxCount = 1;
502 break;
503 #endif
504 case PRIM_LINE:
505 if(drawingKick) Prim_Line();
506 m_vtxCount = 2;
507 break;
508 case PRIM_LINESTRIP:
509 if(drawingKick) Prim_Line();
510 memcpy(&m_vtxBuffer[1], &m_vtxBuffer[0], sizeof(VERTEX));
511 m_vtxCount = 1;
512 break;
513 case PRIM_TRIANGLE:
514 if(drawingKick) Prim_Triangle();
515 m_vtxCount = 3;
516 break;
517 case PRIM_TRIANGLESTRIP:
518 if(drawingKick) Prim_Triangle();
519 memcpy(&m_vtxBuffer[2], &m_vtxBuffer[1], sizeof(VERTEX));
520 memcpy(&m_vtxBuffer[1], &m_vtxBuffer[0], sizeof(VERTEX));
521 m_vtxCount = 1;
522 break;
523 case PRIM_TRIANGLEFAN:
524 if(drawingKick) Prim_Triangle();
525 memcpy(&m_vtxBuffer[1], &m_vtxBuffer[0], sizeof(VERTEX));
526 m_vtxCount = 1;
527 break;
528 case PRIM_SPRITE:
529 if(drawingKick) Prim_Sprite();
530 m_vtxCount = 2;
531 break;
532 }
533 }
534 }
535
SetRenderingContext(uint64 primReg)536 void CGSH_Vulkan::SetRenderingContext(uint64 primReg)
537 {
538 auto prim = make_convertible<PRMODE>(primReg);
539
540 unsigned int context = prim.nContext;
541
542 auto offset = make_convertible<XYOFFSET>(m_nReg[GS_REG_XYOFFSET_1 + context]);
543 auto frame = make_convertible<FRAME>(m_nReg[GS_REG_FRAME_1 + context]);
544 auto zbuf = make_convertible<ZBUF>(m_nReg[GS_REG_ZBUF_1 + context]);
545 auto tex0 = make_convertible<TEX0>(m_nReg[GS_REG_TEX0_1 + context]);
546 auto tex1 = make_convertible<TEX1>(m_nReg[GS_REG_TEX1_1 + context]);
547 auto clamp = make_convertible<CLAMP>(m_nReg[GS_REG_CLAMP_1 + context]);
548 auto alpha = make_convertible<ALPHA>(m_nReg[GS_REG_ALPHA_1 + context]);
549 auto scissor = make_convertible<SCISSOR>(m_nReg[GS_REG_SCISSOR_1 + context]);
550 auto test = make_convertible<TEST>(m_nReg[GS_REG_TEST_1 + context]);
551 auto texA = make_convertible<TEXA>(m_nReg[GS_REG_TEXA]);
552 auto fogCol = make_convertible<FOGCOL>(m_nReg[GS_REG_FOGCOL]);
553
554 auto pipelineCaps = make_convertible<CDraw::PIPELINE_CAPS>(0);
555 pipelineCaps.hasTexture = prim.nTexture;
556 pipelineCaps.textureHasAlpha = tex0.nColorComp;
557 pipelineCaps.textureBlackIsTransparent = texA.nAEM;
558 pipelineCaps.textureFunction = tex0.nFunction;
559 pipelineCaps.texClampU = clamp.nWMS;
560 pipelineCaps.texClampV = clamp.nWMT;
561 pipelineCaps.hasFog = prim.nFog;
562 pipelineCaps.hasAlphaBlending = prim.nAlpha;
563 pipelineCaps.hasDstAlphaTest = test.nDestAlphaEnabled;
564 pipelineCaps.dstAlphaTestRef = test.nDestAlphaMode;
565 pipelineCaps.writeDepth = (zbuf.nMask == 0);
566 pipelineCaps.textureFormat = tex0.nPsm;
567 pipelineCaps.clutFormat = tex0.nCPSM;
568 pipelineCaps.framebufferFormat = frame.nPsm;
569 pipelineCaps.depthbufferFormat = zbuf.nPsm | 0x30;
570
571 switch(m_primitiveType)
572 {
573 default:
574 assert(false);
575 case PRIM_TRIANGLE:
576 case PRIM_TRIANGLEFAN:
577 case PRIM_TRIANGLESTRIP:
578 case PRIM_SPRITE:
579 pipelineCaps.primitiveType = CDraw::PIPELINE_PRIMITIVE_TRIANGLE;
580 break;
581 case PRIM_LINE:
582 case PRIM_LINESTRIP:
583 pipelineCaps.primitiveType = CDraw::PIPELINE_PRIMITIVE_LINE;
584 break;
585 }
586
587 uint32 fbWriteMask = ~frame.nMask;
588
589 if(prim.nTexture)
590 {
591 bool minLinear = false;
592 bool magLinear = false;
593
594 switch(tex1.nMinFilter)
595 {
596 case MIN_FILTER_NEAREST:
597 case MIN_FILTER_NEAREST_MIP_NEAREST:
598 case MIN_FILTER_NEAREST_MIP_LINEAR:
599 minLinear = false;
600 break;
601 case MIN_FILTER_LINEAR:
602 case MIN_FILTER_LINEAR_MIP_NEAREST:
603 case MIN_FILTER_LINEAR_MIP_LINEAR:
604 minLinear = true;
605 break;
606 }
607
608 switch(tex1.nMagFilter)
609 {
610 case MAG_FILTER_NEAREST:
611 magLinear = false;
612 break;
613 case MAG_FILTER_LINEAR:
614 magLinear = true;
615 break;
616 }
617
618 pipelineCaps.textureUseLinearFiltering = (minLinear && magLinear);
619 }
620
621 if(prim.nAlpha)
622 {
623 pipelineCaps.alphaA = alpha.nA;
624 pipelineCaps.alphaB = alpha.nB;
625 pipelineCaps.alphaC = alpha.nC;
626 pipelineCaps.alphaD = alpha.nD;
627 }
628
629 pipelineCaps.depthTestFunction = test.nDepthMethod;
630 if(!test.nDepthEnabled)
631 {
632 pipelineCaps.depthTestFunction = CGSHandler::DEPTH_TEST_ALWAYS;
633 }
634
635 pipelineCaps.alphaTestFunction = test.nAlphaMethod;
636 pipelineCaps.alphaTestFailAction = test.nAlphaFail;
637 if(!test.nAlphaEnabled)
638 {
639 pipelineCaps.alphaTestFunction = CGSHandler::ALPHA_TEST_ALWAYS;
640 }
641
642 //Convert alpha testing to write masking if possible
643 if(
644 (pipelineCaps.alphaTestFunction == CGSHandler::ALPHA_TEST_NEVER) &&
645 (pipelineCaps.alphaTestFailAction == CGSHandler::ALPHA_TEST_FAIL_FBONLY))
646 {
647 pipelineCaps.alphaTestFunction = CGSHandler::ALPHA_TEST_ALWAYS;
648 pipelineCaps.writeDepth = 0;
649 }
650
651 if(
652 (pipelineCaps.alphaTestFunction == CGSHandler::ALPHA_TEST_NEVER) &&
653 (pipelineCaps.alphaTestFailAction == CGSHandler::ALPHA_TEST_FAIL_RGBONLY))
654 {
655 pipelineCaps.alphaTestFunction = CGSHandler::ALPHA_TEST_ALWAYS;
656 pipelineCaps.writeDepth = 0;
657 fbWriteMask &= 0x00FFFFFF;
658 }
659
660 switch(frame.nPsm)
661 {
662 case CGSHandler::PSMCT32:
663 pipelineCaps.maskColor = (fbWriteMask != 0xFFFFFFFF);
664 break;
665 case CGSHandler::PSMCT24:
666 case CGSHandler::PSMZ24:
667 fbWriteMask = fbWriteMask & 0x00FFFFFF;
668 pipelineCaps.maskColor = (fbWriteMask != 0x00FFFFFF);
669 break;
670 case CGSHandler::PSMCT16:
671 case CGSHandler::PSMCT16S:
672 fbWriteMask = RGBA32ToRGBA16(fbWriteMask) & 0xFFFF;
673 pipelineCaps.maskColor = (fbWriteMask != 0xFFFF);
674 break;
675 default:
676 assert(false);
677 break;
678 }
679
680 m_draw->SetPipelineCaps(pipelineCaps);
681 m_draw->SetFramebufferParams(frame.GetBasePtr(), frame.GetWidth(), fbWriteMask);
682 m_draw->SetDepthbufferParams(zbuf.GetBasePtr(), frame.GetWidth());
683 m_draw->SetTextureParams(tex0.GetBufPtr(), tex0.GetBufWidth(),
684 tex0.GetWidth(), tex0.GetHeight(), tex0.nCSA * 0x10);
685 m_draw->SetTextureAlphaParams(texA.nTA0, texA.nTA1);
686 m_draw->SetTextureClampParams(
687 clamp.GetMinU(), clamp.GetMinV(),
688 clamp.GetMaxU(), clamp.GetMaxV());
689 m_draw->SetFogParams(
690 static_cast<float>(fogCol.nFCR) / 255.f,
691 static_cast<float>(fogCol.nFCG) / 255.f,
692 static_cast<float>(fogCol.nFCB) / 255.f);
693 m_draw->SetAlphaBlendingParams(alpha.nFix);
694 m_draw->SetAlphaTestParams(test.nAlphaRef);
695 m_draw->SetScissor(scissor.scax0, scissor.scay0,
696 scissor.scax1 - scissor.scax0 + 1,
697 scissor.scay1 - scissor.scay0 + 1);
698
699 m_primOfsX = offset.GetX();
700 m_primOfsY = offset.GetY();
701
702 m_texWidth = tex0.GetWidth();
703 m_texHeight = tex0.GetHeight();
704 }
705
Prim_Line()706 void CGSH_Vulkan::Prim_Line()
707 {
708 XYZ pos[2];
709 pos[0] <<= m_vtxBuffer[1].position;
710 pos[1] <<= m_vtxBuffer[0].position;
711
712 float x1 = pos[0].GetX(), x2 = pos[1].GetX();
713 float y1 = pos[0].GetY(), y2 = pos[1].GetY();
714 uint32 z1 = pos[0].nZ, z2 = pos[1].nZ;
715
716 RGBAQ rgbaq[2];
717 rgbaq[0] <<= m_vtxBuffer[1].rgbaq;
718 rgbaq[1] <<= m_vtxBuffer[0].rgbaq;
719
720 x1 -= m_primOfsX;
721 x2 -= m_primOfsX;
722
723 y1 -= m_primOfsY;
724 y2 -= m_primOfsY;
725
726 float s[2] = {0, 0};
727 float t[2] = {0, 0};
728 float q[2] = {1, 1};
729
730 if(m_primitiveMode.nTexture)
731 {
732 if(m_primitiveMode.nUseUV)
733 {
734 UV uv[3];
735 uv[0] <<= m_vtxBuffer[1].uv;
736 uv[1] <<= m_vtxBuffer[0].uv;
737
738 s[0] = uv[0].GetU() / static_cast<float>(m_texWidth);
739 s[1] = uv[1].GetU() / static_cast<float>(m_texWidth);
740
741 t[0] = uv[0].GetV() / static_cast<float>(m_texHeight);
742 t[1] = uv[1].GetV() / static_cast<float>(m_texHeight);
743 }
744 else
745 {
746 assert(false);
747 }
748 }
749
750 auto color1 = MakeColor(
751 rgbaq[0].nR, rgbaq[0].nG,
752 rgbaq[0].nB, rgbaq[0].nA);
753
754 auto color2 = MakeColor(
755 rgbaq[1].nR, rgbaq[1].nG,
756 rgbaq[1].nB, rgbaq[1].nA);
757
758 // clang-format off
759 CDraw::PRIM_VERTEX vertices[] =
760 {
761 { x1, y1, z1, color1, s[0], t[0], q[0], 0 },
762 { x2, y2, z2, color2, s[1], t[1], q[1], 0 },
763 };
764 // clang-format on
765
766 m_draw->AddVertices(std::begin(vertices), std::end(vertices));
767 }
768
Prim_Triangle()769 void CGSH_Vulkan::Prim_Triangle()
770 {
771 XYZ pos[3];
772 pos[0] <<= m_vtxBuffer[2].position;
773 pos[1] <<= m_vtxBuffer[1].position;
774 pos[2] <<= m_vtxBuffer[0].position;
775
776 float x1 = pos[0].GetX(), x2 = pos[1].GetX(), x3 = pos[2].GetX();
777 float y1 = pos[0].GetY(), y2 = pos[1].GetY(), y3 = pos[2].GetY();
778 uint32 z1 = pos[0].nZ, z2 = pos[1].nZ, z3 = pos[2].nZ;
779
780 RGBAQ rgbaq[3];
781 rgbaq[0] <<= m_vtxBuffer[2].rgbaq;
782 rgbaq[1] <<= m_vtxBuffer[1].rgbaq;
783 rgbaq[2] <<= m_vtxBuffer[0].rgbaq;
784
785 x1 -= m_primOfsX;
786 x2 -= m_primOfsX;
787 x3 -= m_primOfsX;
788
789 y1 -= m_primOfsY;
790 y2 -= m_primOfsY;
791 y3 -= m_primOfsY;
792
793 float s[3] = {0, 0, 0};
794 float t[3] = {0, 0, 0};
795 float q[3] = {1, 1, 1};
796
797 float f[3] = {0, 0, 0};
798
799 if(m_primitiveMode.nFog)
800 {
801 f[0] = static_cast<float>(0xFF - m_vtxBuffer[2].fog) / 255.0f;
802 f[1] = static_cast<float>(0xFF - m_vtxBuffer[1].fog) / 255.0f;
803 f[2] = static_cast<float>(0xFF - m_vtxBuffer[0].fog) / 255.0f;
804 }
805
806 if(m_primitiveMode.nTexture)
807 {
808 if(m_primitiveMode.nUseUV)
809 {
810 UV uv[3];
811 uv[0] <<= m_vtxBuffer[2].uv;
812 uv[1] <<= m_vtxBuffer[1].uv;
813 uv[2] <<= m_vtxBuffer[0].uv;
814
815 s[0] = uv[0].GetU() / static_cast<float>(m_texWidth);
816 s[1] = uv[1].GetU() / static_cast<float>(m_texWidth);
817 s[2] = uv[2].GetU() / static_cast<float>(m_texWidth);
818
819 t[0] = uv[0].GetV() / static_cast<float>(m_texHeight);
820 t[1] = uv[1].GetV() / static_cast<float>(m_texHeight);
821 t[2] = uv[2].GetV() / static_cast<float>(m_texHeight);
822 }
823 else
824 {
825 ST st[3];
826 st[0] <<= m_vtxBuffer[2].st;
827 st[1] <<= m_vtxBuffer[1].st;
828 st[2] <<= m_vtxBuffer[0].st;
829
830 s[0] = st[0].nS;
831 s[1] = st[1].nS;
832 s[2] = st[2].nS;
833 t[0] = st[0].nT;
834 t[1] = st[1].nT;
835 t[2] = st[2].nT;
836
837 q[0] = rgbaq[0].nQ;
838 q[1] = rgbaq[1].nQ;
839 q[2] = rgbaq[2].nQ;
840 }
841 }
842
843 auto color1 = MakeColor(
844 rgbaq[0].nR, rgbaq[0].nG,
845 rgbaq[0].nB, rgbaq[0].nA);
846
847 auto color2 = MakeColor(
848 rgbaq[1].nR, rgbaq[1].nG,
849 rgbaq[1].nB, rgbaq[1].nA);
850
851 auto color3 = MakeColor(
852 rgbaq[2].nR, rgbaq[2].nG,
853 rgbaq[2].nB, rgbaq[2].nA);
854
855 if(m_primitiveMode.nShading == 0)
856 {
857 //Flat shaded triangles use the last color set
858 color1 = color2 = color3;
859 }
860
861 // clang-format off
862 CDraw::PRIM_VERTEX vertices[] =
863 {
864 { x1, y1, z1, color1, s[0], t[0], q[0], f[0]},
865 { x2, y2, z2, color2, s[1], t[1], q[1], f[1]},
866 { x3, y3, z3, color3, s[2], t[2], q[2], f[2]},
867 };
868 // clang-format on
869
870 m_draw->AddVertices(std::begin(vertices), std::end(vertices));
871 }
872
Prim_Sprite()873 void CGSH_Vulkan::Prim_Sprite()
874 {
875 XYZ pos[2];
876 pos[0] <<= m_vtxBuffer[1].position;
877 pos[1] <<= m_vtxBuffer[0].position;
878
879 float x1 = pos[0].GetX(), y1 = pos[0].GetY();
880 float x2 = pos[1].GetX(), y2 = pos[1].GetY();
881 uint32 z = pos[1].nZ;
882
883 RGBAQ rgbaq[2];
884 rgbaq[0] <<= m_vtxBuffer[1].rgbaq;
885 rgbaq[1] <<= m_vtxBuffer[0].rgbaq;
886
887 x1 -= m_primOfsX;
888 x2 -= m_primOfsX;
889
890 y1 -= m_primOfsY;
891 y2 -= m_primOfsY;
892
893 float s[2] = {0, 0};
894 float t[2] = {0, 0};
895
896 if(m_primitiveMode.nTexture)
897 {
898 if(m_primitiveMode.nUseUV)
899 {
900 UV uv[2];
901 uv[0] <<= m_vtxBuffer[1].uv;
902 uv[1] <<= m_vtxBuffer[0].uv;
903
904 s[0] = uv[0].GetU() / static_cast<float>(m_texWidth);
905 s[1] = uv[1].GetU() / static_cast<float>(m_texWidth);
906
907 t[0] = uv[0].GetV() / static_cast<float>(m_texHeight);
908 t[1] = uv[1].GetV() / static_cast<float>(m_texHeight);
909 }
910 else
911 {
912 ST st[2];
913
914 st[0] <<= m_vtxBuffer[1].st;
915 st[1] <<= m_vtxBuffer[0].st;
916
917 float q1 = rgbaq[1].nQ;
918 float q2 = rgbaq[0].nQ;
919 if(q1 == 0) q1 = 1;
920 if(q2 == 0) q2 = 1;
921
922 s[0] = st[0].nS / q1;
923 s[1] = st[1].nS / q2;
924
925 t[0] = st[0].nT / q1;
926 t[1] = st[1].nT / q2;
927 }
928 }
929
930 auto color = MakeColor(
931 rgbaq[1].nR, rgbaq[1].nG,
932 rgbaq[1].nB, rgbaq[1].nA);
933
934 // clang-format off
935 CDraw::PRIM_VERTEX vertices[] =
936 {
937 {x1, y1, z, color, s[0], t[0], 1, 0},
938 {x2, y1, z, color, s[1], t[0], 1, 0},
939 {x1, y2, z, color, s[0], t[1], 1, 0},
940
941 {x1, y2, z, color, s[0], t[1], 1, 0},
942 {x2, y1, z, color, s[1], t[0], 1, 0},
943 {x2, y2, z, color, s[1], t[1], 1, 0},
944 };
945 // clang-format on
946
947 m_draw->AddVertices(std::begin(vertices), std::end(vertices));
948 }
949
FindCachedClut(const CLUTKEY & key) const950 int32 CGSH_Vulkan::FindCachedClut(const CLUTKEY& key) const
951 {
952 for(uint32 i = 0; i < CLUT_CACHE_SIZE; i++)
953 {
954 if(m_clutStates[i] == key)
955 {
956 return i;
957 }
958 }
959 return -1;
960 }
961
MakeCachedClutKey(const TEX0 & tex0,const TEXCLUT & texClut)962 CGSH_Vulkan::CLUTKEY CGSH_Vulkan::MakeCachedClutKey(const TEX0& tex0, const TEXCLUT& texClut)
963 {
964 auto clutKey = make_convertible<CLUTKEY>(0);
965 clutKey.idx4 = CGsPixelFormats::IsPsmIDTEX4(tex0.nPsm);
966 clutKey.cbp = tex0.nCBP;
967 clutKey.cpsm = tex0.nCPSM;
968 clutKey.csm = tex0.nCSM;
969 clutKey.csa = tex0.nCSA;
970 clutKey.cbw = texClut.nCBW;
971 clutKey.cou = texClut.nCOU;
972 clutKey.cov = texClut.nCOV;
973 return clutKey;
974 }
975
976 /////////////////////////////////////////////////////////////
977 // Other Functions
978 /////////////////////////////////////////////////////////////
979
WriteRegisterImpl(uint8 registerId,uint64 data)980 void CGSH_Vulkan::WriteRegisterImpl(uint8 registerId, uint64 data)
981 {
982 //Some games such as Silent Hill 2 don't finish their transfers
983 //completely: make sure we push the data to the GS's RAM nevertheless.
984 if(!m_xferBuffer.empty())
985 {
986 ProcessHostToLocalTransfer();
987 }
988
989 CGSHandler::WriteRegisterImpl(registerId, data);
990
991 switch(registerId)
992 {
993 case GS_REG_PRIM:
994 {
995 unsigned int newPrimitiveType = static_cast<unsigned int>(data & 0x07);
996 if(newPrimitiveType != m_primitiveType)
997 {
998 m_draw->FlushVertices();
999 }
1000 m_primitiveType = newPrimitiveType;
1001 switch(m_primitiveType)
1002 {
1003 case PRIM_POINT:
1004 m_vtxCount = 1;
1005 break;
1006 case PRIM_LINE:
1007 case PRIM_LINESTRIP:
1008 m_vtxCount = 2;
1009 break;
1010 case PRIM_TRIANGLE:
1011 case PRIM_TRIANGLESTRIP:
1012 case PRIM_TRIANGLEFAN:
1013 m_vtxCount = 3;
1014 break;
1015 case PRIM_SPRITE:
1016 m_vtxCount = 2;
1017 break;
1018 }
1019 }
1020 break;
1021
1022 case GS_REG_XYZ2:
1023 case GS_REG_XYZ3:
1024 case GS_REG_XYZF2:
1025 case GS_REG_XYZF3:
1026 VertexKick(registerId, data);
1027 break;
1028 }
1029 }
1030
ProcessHostToLocalTransfer()1031 void CGSH_Vulkan::ProcessHostToLocalTransfer()
1032 {
1033 //Flush previous cached info
1034 memset(&m_clutStates, 0, sizeof(m_clutStates));
1035 m_draw->FlushRenderPass();
1036
1037 auto bltBuf = make_convertible<BITBLTBUF>(m_nReg[GS_REG_BITBLTBUF]);
1038 auto trxReg = make_convertible<TRXREG>(m_nReg[GS_REG_TRXREG]);
1039 auto trxPos = make_convertible<TRXPOS>(m_nReg[GS_REG_TRXPOS]);
1040
1041 m_transferHost->Params.bufAddress = bltBuf.GetDstPtr();
1042 m_transferHost->Params.bufWidth = bltBuf.GetDstWidth();
1043 m_transferHost->Params.rrw = trxReg.nRRW;
1044 m_transferHost->Params.dsax = trxPos.nDSAX;
1045 m_transferHost->Params.dsay = trxPos.nDSAY;
1046
1047 auto pipelineCaps = make_convertible<CTransferHost::PIPELINE_CAPS>(0);
1048 pipelineCaps.dstFormat = bltBuf.nDstPsm;
1049
1050 m_transferHost->SetPipelineCaps(pipelineCaps);
1051 m_transferHost->DoTransfer(m_xferBuffer);
1052
1053 m_xferBuffer.clear();
1054 }
1055
ProcessLocalToHostTransfer()1056 void CGSH_Vulkan::ProcessLocalToHostTransfer()
1057 {
1058 //We're about to read from GS RAM, make sure all rendering commands are complete
1059 m_frameCommandBuffer->Flush();
1060 m_context->device.vkQueueWaitIdle(m_context->queue);
1061 }
1062
ProcessLocalToLocalTransfer()1063 void CGSH_Vulkan::ProcessLocalToLocalTransfer()
1064 {
1065 //Flush previous cached info
1066 memset(&m_clutStates, 0, sizeof(m_clutStates));
1067 m_draw->FlushRenderPass();
1068
1069 auto bltBuf = make_convertible<BITBLTBUF>(m_nReg[GS_REG_BITBLTBUF]);
1070 auto trxReg = make_convertible<TRXREG>(m_nReg[GS_REG_TRXREG]);
1071 auto trxPos = make_convertible<TRXPOS>(m_nReg[GS_REG_TRXPOS]);
1072
1073 assert(trxPos.nDIR == 0);
1074
1075 m_transferLocal->Params.srcBufAddress = bltBuf.GetSrcPtr();
1076 m_transferLocal->Params.srcBufWidth = bltBuf.GetSrcWidth();
1077 m_transferLocal->Params.dstBufAddress = bltBuf.GetDstPtr();
1078 m_transferLocal->Params.dstBufWidth = bltBuf.GetDstWidth();
1079 m_transferLocal->Params.ssax = trxPos.nSSAX;
1080 m_transferLocal->Params.ssay = trxPos.nSSAY;
1081 m_transferLocal->Params.dsax = trxPos.nDSAX;
1082 m_transferLocal->Params.dsay = trxPos.nDSAY;
1083 m_transferLocal->Params.rrw = trxReg.nRRW;
1084 m_transferLocal->Params.rrh = trxReg.nRRH;
1085
1086 auto pipelineCaps = make_convertible<CTransferLocal::PIPELINE_CAPS>(0);
1087 pipelineCaps.srcFormat = bltBuf.nSrcPsm;
1088 pipelineCaps.dstFormat = bltBuf.nDstPsm;
1089
1090 m_transferLocal->SetPipelineCaps(pipelineCaps);
1091 m_transferLocal->DoTransfer();
1092 }
1093
ProcessClutTransfer(uint32 csa,uint32)1094 void CGSH_Vulkan::ProcessClutTransfer(uint32 csa, uint32)
1095 {
1096 }
1097
BeginTransferWrite()1098 void CGSH_Vulkan::BeginTransferWrite()
1099 {
1100 assert(m_xferBuffer.empty());
1101 m_xferBuffer.clear();
1102 }
1103
TransferWrite(const uint8 * imageData,uint32 length)1104 void CGSH_Vulkan::TransferWrite(const uint8* imageData, uint32 length)
1105 {
1106 m_xferBuffer.insert(m_xferBuffer.end(), imageData, imageData + length);
1107 }
1108
SyncCLUT(const TEX0 & tex0)1109 void CGSH_Vulkan::SyncCLUT(const TEX0& tex0)
1110 {
1111 if(!CGsPixelFormats::IsPsmIDTEX(tex0.nPsm)) return;
1112 if(!ProcessCLD(tex0)) return;
1113
1114 auto texClut = make_convertible<TEXCLUT>(m_nReg[GS_REG_TEXCLUT]);
1115
1116 auto clutKey = MakeCachedClutKey(tex0, texClut);
1117 int32 clutCacheIndex = FindCachedClut(clutKey);
1118 if(clutCacheIndex == -1)
1119 {
1120 clutCacheIndex = m_nextClutCacheIndex++;
1121 m_nextClutCacheIndex %= CLUT_CACHE_SIZE;
1122 m_clutStates[clutCacheIndex] = clutKey;
1123
1124 m_draw->FlushRenderPass();
1125 uint32 clutBufferOffset = sizeof(uint32) * CLUTENTRYCOUNT * clutCacheIndex;
1126 m_clutLoad->DoClutLoad(clutBufferOffset, tex0, texClut);
1127 }
1128
1129 uint32 clutBufferOffset = sizeof(uint32) * CLUTENTRYCOUNT * clutCacheIndex;
1130 m_draw->SetClutBufferOffset(clutBufferOffset);
1131 }
1132
ReadFramebuffer(uint32 width,uint32 height,void * buffer)1133 void CGSH_Vulkan::ReadFramebuffer(uint32 width, uint32 height, void* buffer)
1134 {
1135 }
1136
GetRam() const1137 uint8* CGSH_Vulkan::GetRam() const
1138 {
1139 return m_memoryBufferPtr;
1140 }
1141
GetScreenshot()1142 Framework::CBitmap CGSH_Vulkan::GetScreenshot()
1143 {
1144 return Framework::CBitmap();
1145 }
1146