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