1 // Copyright 2016 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4 
5 #include "VideoBackends/Vulkan/VertexManager.h"
6 
7 #include "Common/Align.h"
8 #include "Common/CommonTypes.h"
9 #include "Common/Logging/Log.h"
10 #include "Common/MsgHandler.h"
11 
12 #include "VideoBackends/Vulkan/CommandBufferManager.h"
13 #include "VideoBackends/Vulkan/Renderer.h"
14 #include "VideoBackends/Vulkan/StateTracker.h"
15 #include "VideoBackends/Vulkan/StreamBuffer.h"
16 #include "VideoBackends/Vulkan/VertexFormat.h"
17 #include "VideoBackends/Vulkan/VulkanContext.h"
18 
19 #include "VideoCommon/GeometryShaderManager.h"
20 #include "VideoCommon/IndexGenerator.h"
21 #include "VideoCommon/PixelShaderManager.h"
22 #include "VideoCommon/Statistics.h"
23 #include "VideoCommon/VertexLoaderManager.h"
24 #include "VideoCommon/VertexShaderManager.h"
25 #include "VideoCommon/VideoConfig.h"
26 
27 namespace Vulkan
28 {
CreateTexelBufferView(VkBuffer buffer,VkFormat vk_format)29 static VkBufferView CreateTexelBufferView(VkBuffer buffer, VkFormat vk_format)
30 {
31   // Create a view of the whole buffer, we'll offset our texel load into it
32   VkBufferViewCreateInfo view_info = {
33       VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,  // VkStructureType            sType
34       nullptr,                                    // const void*                pNext
35       0,                                          // VkBufferViewCreateFlags    flags
36       buffer,                                     // VkBuffer                   buffer
37       vk_format,                                  // VkFormat                   format
38       0,                                          // VkDeviceSize               offset
39       VK_WHOLE_SIZE                               // VkDeviceSize               range
40   };
41 
42   VkBufferView view;
43   VkResult res = vkCreateBufferView(g_vulkan_context->GetDevice(), &view_info, nullptr, &view);
44   if (res != VK_SUCCESS)
45   {
46     LOG_VULKAN_ERROR(res, "vkCreateBufferView failed: ");
47     return VK_NULL_HANDLE;
48   }
49 
50   return view;
51 }
52 
53 VertexManager::VertexManager() = default;
54 
~VertexManager()55 VertexManager::~VertexManager()
56 {
57   DestroyTexelBufferViews();
58 }
59 
Initialize()60 bool VertexManager::Initialize()
61 {
62   if (!VertexManagerBase::Initialize())
63     return false;
64 
65   m_vertex_stream_buffer =
66       StreamBuffer::Create(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VERTEX_STREAM_BUFFER_SIZE);
67   m_index_stream_buffer =
68       StreamBuffer::Create(VK_BUFFER_USAGE_INDEX_BUFFER_BIT, INDEX_STREAM_BUFFER_SIZE);
69   m_uniform_stream_buffer =
70       StreamBuffer::Create(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, UNIFORM_STREAM_BUFFER_SIZE);
71   if (!m_vertex_stream_buffer || !m_index_stream_buffer || !m_uniform_stream_buffer)
72   {
73     PanicAlert("Failed to allocate streaming buffers");
74     return false;
75   }
76 
77   // The validation layer complains if max(offsets) + max(ubo_ranges) >= ubo_size.
78   // To work around this we reserve the maximum buffer size at all times, but only commit
79   // as many bytes as we use.
80   m_uniform_buffer_reserve_size = sizeof(PixelShaderConstants);
81   m_uniform_buffer_reserve_size = Common::AlignUp(m_uniform_buffer_reserve_size,
82                                                   g_vulkan_context->GetUniformBufferAlignment()) +
83                                   sizeof(VertexShaderConstants);
84   m_uniform_buffer_reserve_size = Common::AlignUp(m_uniform_buffer_reserve_size,
85                                                   g_vulkan_context->GetUniformBufferAlignment()) +
86                                   sizeof(GeometryShaderConstants);
87 
88   // Prefer an 8MB buffer if possible, but use less if the device doesn't support this.
89   // This buffer is potentially going to be addressed as R8s in the future, so we assume
90   // that one element is one byte. This doesn't use min() because of a NDK compiler bug..
91   const u32 texel_buffer_size =
92       TEXEL_STREAM_BUFFER_SIZE > g_vulkan_context->GetDeviceLimits().maxTexelBufferElements ?
93           g_vulkan_context->GetDeviceLimits().maxTexelBufferElements :
94           TEXEL_STREAM_BUFFER_SIZE;
95   m_texel_stream_buffer =
96       StreamBuffer::Create(VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, texel_buffer_size);
97   if (!m_texel_stream_buffer)
98   {
99     PanicAlert("Failed to allocate streaming texel buffer");
100     return false;
101   }
102 
103   static constexpr std::array<std::pair<TexelBufferFormat, VkFormat>, NUM_TEXEL_BUFFER_FORMATS>
104       format_mapping = {{
105           {TEXEL_BUFFER_FORMAT_R8_UINT, VK_FORMAT_R8_UINT},
106           {TEXEL_BUFFER_FORMAT_R16_UINT, VK_FORMAT_R16_UINT},
107           {TEXEL_BUFFER_FORMAT_RGBA8_UINT, VK_FORMAT_R8G8B8A8_UINT},
108           {TEXEL_BUFFER_FORMAT_R32G32_UINT, VK_FORMAT_R32G32_UINT},
109       }};
110   for (const auto& it : format_mapping)
111   {
112     if ((m_texel_buffer_views[it.first] = CreateTexelBufferView(m_texel_stream_buffer->GetBuffer(),
113                                                                 it.second)) == VK_NULL_HANDLE)
114     {
115       PanicAlert("Failed to create texel buffer view");
116       return false;
117     }
118   }
119 
120   // Bind the buffers to all the known spots even if it's not used, to keep the driver happy.
121   UploadAllConstants();
122   StateTracker::GetInstance()->SetUtilityUniformBuffer(m_uniform_stream_buffer->GetBuffer(), 0,
123                                                        sizeof(VertexShaderConstants));
124   for (u32 i = 0; i < NUM_COMPUTE_TEXEL_BUFFERS; i++)
125   {
126     StateTracker::GetInstance()->SetTexelBuffer(i,
127                                                 m_texel_buffer_views[TEXEL_BUFFER_FORMAT_R8_UINT]);
128   }
129 
130   return true;
131 }
132 
DestroyTexelBufferViews()133 void VertexManager::DestroyTexelBufferViews()
134 {
135   for (VkBufferView view : m_texel_buffer_views)
136   {
137     if (view != VK_NULL_HANDLE)
138       vkDestroyBufferView(g_vulkan_context->GetDevice(), view, nullptr);
139   }
140 }
141 
ResetBuffer(u32 vertex_stride)142 void VertexManager::ResetBuffer(u32 vertex_stride)
143 {
144   // Attempt to allocate from buffers
145   bool has_vbuffer_allocation =
146       m_vertex_stream_buffer->ReserveMemory(MAXVBUFFERSIZE, vertex_stride);
147   bool has_ibuffer_allocation =
148       m_index_stream_buffer->ReserveMemory(MAXIBUFFERSIZE * sizeof(u16), sizeof(u16));
149   if (!has_vbuffer_allocation || !has_ibuffer_allocation)
150   {
151     // Flush any pending commands first, so that we can wait on the fences
152     WARN_LOG(VIDEO, "Executing command list while waiting for space in vertex/index buffer");
153     Renderer::GetInstance()->ExecuteCommandBuffer(false);
154 
155     // Attempt to allocate again, this may cause a fence wait
156     if (!has_vbuffer_allocation)
157       has_vbuffer_allocation = m_vertex_stream_buffer->ReserveMemory(MAXVBUFFERSIZE, vertex_stride);
158     if (!has_ibuffer_allocation)
159       has_ibuffer_allocation =
160           m_index_stream_buffer->ReserveMemory(MAXIBUFFERSIZE * sizeof(u16), sizeof(u16));
161 
162     // If we still failed, that means the allocation was too large and will never succeed, so panic
163     if (!has_vbuffer_allocation || !has_ibuffer_allocation)
164       PanicAlert("Failed to allocate space in streaming buffers for pending draw");
165   }
166 
167   // Update pointers
168   m_base_buffer_pointer = m_vertex_stream_buffer->GetHostPointer();
169   m_end_buffer_pointer = m_vertex_stream_buffer->GetCurrentHostPointer() + MAXVBUFFERSIZE;
170   m_cur_buffer_pointer = m_vertex_stream_buffer->GetCurrentHostPointer();
171   m_index_generator.Start(reinterpret_cast<u16*>(m_index_stream_buffer->GetCurrentHostPointer()));
172 }
173 
CommitBuffer(u32 num_vertices,u32 vertex_stride,u32 num_indices,u32 * out_base_vertex,u32 * out_base_index)174 void VertexManager::CommitBuffer(u32 num_vertices, u32 vertex_stride, u32 num_indices,
175                                  u32* out_base_vertex, u32* out_base_index)
176 {
177   const u32 vertex_data_size = num_vertices * vertex_stride;
178   const u32 index_data_size = num_indices * sizeof(u16);
179 
180   *out_base_vertex =
181       vertex_stride > 0 ? (m_vertex_stream_buffer->GetCurrentOffset() / vertex_stride) : 0;
182   *out_base_index = m_index_stream_buffer->GetCurrentOffset() / sizeof(u16);
183 
184   m_vertex_stream_buffer->CommitMemory(vertex_data_size);
185   m_index_stream_buffer->CommitMemory(index_data_size);
186 
187   ADDSTAT(g_stats.this_frame.bytes_vertex_streamed, static_cast<int>(vertex_data_size));
188   ADDSTAT(g_stats.this_frame.bytes_index_streamed, static_cast<int>(index_data_size));
189 
190   StateTracker::GetInstance()->SetVertexBuffer(m_vertex_stream_buffer->GetBuffer(), 0);
191   StateTracker::GetInstance()->SetIndexBuffer(m_index_stream_buffer->GetBuffer(), 0,
192                                               VK_INDEX_TYPE_UINT16);
193 }
194 
UploadUniforms()195 void VertexManager::UploadUniforms()
196 {
197   UpdateVertexShaderConstants();
198   UpdateGeometryShaderConstants();
199   UpdatePixelShaderConstants();
200 }
201 
UpdateVertexShaderConstants()202 void VertexManager::UpdateVertexShaderConstants()
203 {
204   if (!VertexShaderManager::dirty || !ReserveConstantStorage())
205     return;
206 
207   StateTracker::GetInstance()->SetGXUniformBuffer(
208       UBO_DESCRIPTOR_SET_BINDING_VS, m_uniform_stream_buffer->GetBuffer(),
209       m_uniform_stream_buffer->GetCurrentOffset(), sizeof(VertexShaderConstants));
210   std::memcpy(m_uniform_stream_buffer->GetCurrentHostPointer(), &VertexShaderManager::constants,
211               sizeof(VertexShaderConstants));
212   m_uniform_stream_buffer->CommitMemory(sizeof(VertexShaderConstants));
213   ADDSTAT(g_stats.this_frame.bytes_uniform_streamed, sizeof(VertexShaderConstants));
214   VertexShaderManager::dirty = false;
215 }
216 
UpdateGeometryShaderConstants()217 void VertexManager::UpdateGeometryShaderConstants()
218 {
219   if (!GeometryShaderManager::dirty || !ReserveConstantStorage())
220     return;
221 
222   StateTracker::GetInstance()->SetGXUniformBuffer(
223       UBO_DESCRIPTOR_SET_BINDING_GS, m_uniform_stream_buffer->GetBuffer(),
224       m_uniform_stream_buffer->GetCurrentOffset(), sizeof(GeometryShaderConstants));
225   std::memcpy(m_uniform_stream_buffer->GetCurrentHostPointer(), &GeometryShaderManager::constants,
226               sizeof(GeometryShaderConstants));
227   m_uniform_stream_buffer->CommitMemory(sizeof(GeometryShaderConstants));
228   ADDSTAT(g_stats.this_frame.bytes_uniform_streamed, sizeof(GeometryShaderConstants));
229   GeometryShaderManager::dirty = false;
230 }
231 
UpdatePixelShaderConstants()232 void VertexManager::UpdatePixelShaderConstants()
233 {
234   if (!PixelShaderManager::dirty || !ReserveConstantStorage())
235     return;
236 
237   StateTracker::GetInstance()->SetGXUniformBuffer(
238       UBO_DESCRIPTOR_SET_BINDING_PS, m_uniform_stream_buffer->GetBuffer(),
239       m_uniform_stream_buffer->GetCurrentOffset(), sizeof(PixelShaderConstants));
240   std::memcpy(m_uniform_stream_buffer->GetCurrentHostPointer(), &PixelShaderManager::constants,
241               sizeof(PixelShaderConstants));
242   m_uniform_stream_buffer->CommitMemory(sizeof(PixelShaderConstants));
243   ADDSTAT(g_stats.this_frame.bytes_uniform_streamed, sizeof(PixelShaderConstants));
244   PixelShaderManager::dirty = false;
245 }
246 
ReserveConstantStorage()247 bool VertexManager::ReserveConstantStorage()
248 {
249   if (m_uniform_stream_buffer->ReserveMemory(m_uniform_buffer_reserve_size,
250                                              g_vulkan_context->GetUniformBufferAlignment()))
251   {
252     return true;
253   }
254 
255   // The only places that call constant updates are safe to have state restored.
256   WARN_LOG(VIDEO, "Executing command buffer while waiting for space in uniform buffer");
257   Renderer::GetInstance()->ExecuteCommandBuffer(false);
258 
259   // Since we are on a new command buffer, all constants have been invalidated, and we need
260   // to reupload them. We may as well do this now, since we're issuing a draw anyway.
261   UploadAllConstants();
262   return false;
263 }
264 
UploadAllConstants()265 void VertexManager::UploadAllConstants()
266 {
267   // We are free to re-use parts of the buffer now since we're uploading all constants.
268   const u32 ub_alignment = static_cast<u32>(g_vulkan_context->GetUniformBufferAlignment());
269   const u32 pixel_constants_offset = 0;
270   const u32 vertex_constants_offset =
271       Common::AlignUp(pixel_constants_offset + sizeof(PixelShaderConstants), ub_alignment);
272   const u32 geometry_constants_offset =
273       Common::AlignUp(vertex_constants_offset + sizeof(VertexShaderConstants), ub_alignment);
274   const u32 allocation_size = geometry_constants_offset + sizeof(GeometryShaderConstants);
275 
276   // Allocate everything at once.
277   // We should only be here if the buffer was full and a command buffer was submitted anyway.
278   if (!m_uniform_stream_buffer->ReserveMemory(allocation_size, ub_alignment))
279   {
280     PanicAlert("Failed to allocate space for constants in streaming buffer");
281     return;
282   }
283 
284   // Update bindings
285   StateTracker::GetInstance()->SetGXUniformBuffer(
286       UBO_DESCRIPTOR_SET_BINDING_PS, m_uniform_stream_buffer->GetBuffer(),
287       m_uniform_stream_buffer->GetCurrentOffset() + pixel_constants_offset,
288       sizeof(PixelShaderConstants));
289   StateTracker::GetInstance()->SetGXUniformBuffer(
290       UBO_DESCRIPTOR_SET_BINDING_VS, m_uniform_stream_buffer->GetBuffer(),
291       m_uniform_stream_buffer->GetCurrentOffset() + vertex_constants_offset,
292       sizeof(VertexShaderConstants));
293   StateTracker::GetInstance()->SetGXUniformBuffer(
294       UBO_DESCRIPTOR_SET_BINDING_GS, m_uniform_stream_buffer->GetBuffer(),
295       m_uniform_stream_buffer->GetCurrentOffset() + geometry_constants_offset,
296       sizeof(GeometryShaderConstants));
297 
298   // Copy the actual data in
299   std::memcpy(m_uniform_stream_buffer->GetCurrentHostPointer() + pixel_constants_offset,
300               &PixelShaderManager::constants, sizeof(PixelShaderConstants));
301   std::memcpy(m_uniform_stream_buffer->GetCurrentHostPointer() + vertex_constants_offset,
302               &VertexShaderManager::constants, sizeof(VertexShaderConstants));
303   std::memcpy(m_uniform_stream_buffer->GetCurrentHostPointer() + geometry_constants_offset,
304               &GeometryShaderManager::constants, sizeof(GeometryShaderConstants));
305 
306   // Finally, flush buffer memory after copying
307   m_uniform_stream_buffer->CommitMemory(allocation_size);
308   ADDSTAT(g_stats.this_frame.bytes_uniform_streamed, allocation_size);
309 
310   // Clear dirty flags
311   VertexShaderManager::dirty = false;
312   GeometryShaderManager::dirty = false;
313   PixelShaderManager::dirty = false;
314 }
315 
UploadUtilityUniforms(const void * data,u32 data_size)316 void VertexManager::UploadUtilityUniforms(const void* data, u32 data_size)
317 {
318   InvalidateConstants();
319   if (!m_uniform_stream_buffer->ReserveMemory(data_size,
320                                               g_vulkan_context->GetUniformBufferAlignment()))
321   {
322     WARN_LOG(VIDEO, "Executing command buffer while waiting for ext space in uniform buffer");
323     Renderer::GetInstance()->ExecuteCommandBuffer(false);
324   }
325 
326   StateTracker::GetInstance()->SetUtilityUniformBuffer(
327       m_uniform_stream_buffer->GetBuffer(), m_uniform_stream_buffer->GetCurrentOffset(), data_size);
328   std::memcpy(m_uniform_stream_buffer->GetCurrentHostPointer(), data, data_size);
329   m_uniform_stream_buffer->CommitMemory(data_size);
330   ADDSTAT(g_stats.this_frame.bytes_uniform_streamed, data_size);
331 }
332 
UploadTexelBuffer(const void * data,u32 data_size,TexelBufferFormat format,u32 * out_offset)333 bool VertexManager::UploadTexelBuffer(const void* data, u32 data_size, TexelBufferFormat format,
334                                       u32* out_offset)
335 {
336   if (data_size > m_texel_stream_buffer->GetCurrentSize())
337     return false;
338 
339   const u32 elem_size = GetTexelBufferElementSize(format);
340   if (!m_texel_stream_buffer->ReserveMemory(data_size, elem_size))
341   {
342     // Try submitting cmdbuffer.
343     WARN_LOG(VIDEO, "Submitting command buffer while waiting for space in texel buffer");
344     Renderer::GetInstance()->ExecuteCommandBuffer(false, false);
345     if (!m_texel_stream_buffer->ReserveMemory(data_size, elem_size))
346     {
347       PanicAlert("Failed to allocate %u bytes from texel buffer", data_size);
348       return false;
349     }
350   }
351 
352   std::memcpy(m_texel_stream_buffer->GetCurrentHostPointer(), data, data_size);
353   *out_offset = static_cast<u32>(m_texel_stream_buffer->GetCurrentOffset()) / elem_size;
354   m_texel_stream_buffer->CommitMemory(data_size);
355   ADDSTAT(g_stats.this_frame.bytes_uniform_streamed, data_size);
356   StateTracker::GetInstance()->SetTexelBuffer(0, m_texel_buffer_views[format]);
357   return true;
358 }
359 
UploadTexelBuffer(const void * data,u32 data_size,TexelBufferFormat format,u32 * out_offset,const void * palette_data,u32 palette_size,TexelBufferFormat palette_format,u32 * out_palette_offset)360 bool VertexManager::UploadTexelBuffer(const void* data, u32 data_size, TexelBufferFormat format,
361                                       u32* out_offset, const void* palette_data, u32 palette_size,
362                                       TexelBufferFormat palette_format, u32* out_palette_offset)
363 {
364   const u32 elem_size = GetTexelBufferElementSize(format);
365   const u32 palette_elem_size = GetTexelBufferElementSize(palette_format);
366   const u32 reserve_size = data_size + palette_size + palette_elem_size;
367   if (reserve_size > m_texel_stream_buffer->GetCurrentSize())
368     return false;
369 
370   if (!m_texel_stream_buffer->ReserveMemory(reserve_size, elem_size))
371   {
372     // Try submitting cmdbuffer.
373     WARN_LOG(VIDEO, "Submitting command buffer while waiting for space in texel buffer");
374     Renderer::GetInstance()->ExecuteCommandBuffer(false, false);
375     if (!m_texel_stream_buffer->ReserveMemory(reserve_size, elem_size))
376     {
377       PanicAlert("Failed to allocate %u bytes from texel buffer", reserve_size);
378       return false;
379     }
380   }
381 
382   const u32 palette_byte_offset = Common::AlignUp(data_size, palette_elem_size);
383   std::memcpy(m_texel_stream_buffer->GetCurrentHostPointer(), data, data_size);
384   std::memcpy(m_texel_stream_buffer->GetCurrentHostPointer() + palette_byte_offset, palette_data,
385               palette_size);
386   *out_offset = static_cast<u32>(m_texel_stream_buffer->GetCurrentOffset()) / elem_size;
387   *out_palette_offset =
388       (static_cast<u32>(m_texel_stream_buffer->GetCurrentOffset()) + palette_byte_offset) /
389       palette_elem_size;
390 
391   m_texel_stream_buffer->CommitMemory(palette_byte_offset + palette_size);
392   ADDSTAT(g_stats.this_frame.bytes_uniform_streamed, palette_byte_offset + palette_size);
393   StateTracker::GetInstance()->SetTexelBuffer(0, m_texel_buffer_views[format]);
394   StateTracker::GetInstance()->SetTexelBuffer(1, m_texel_buffer_views[palette_format]);
395   return true;
396 }
397 }  // namespace Vulkan
398