CommandBufferBuilder.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /*
  2. * Copyright (c) 2022, Sahan Fernando <sahan.h.fernando@gmail.com>
  3. * Copyright (c) 2022, Stephan Unverwerth <s.unverwerth@serenityos.org>
  4. * Copyright (c) 2022, the SerenityOS developers.
  5. *
  6. * SPDX-License-Identifier: BSD-2-Clause
  7. */
  8. #include <AK/StringView.h>
  9. #include <Kernel/API/VirGL.h>
  10. #include <sys/ioctl_numbers.h>
  11. #include <LibVirtGPU/CommandBufferBuilder.h>
  12. #include <LibVirtGPU/VirGLProtocol.h>
  13. namespace VirtGPU {
  14. static u32 encode_command(u16 length, Protocol::ObjectType object_type, Protocol::VirGLCommand command)
  15. {
  16. u8 command_value = to_underlying(command);
  17. u8 object_type_value = to_underlying(object_type);
  18. return (length << 16) | (object_type_value << 8) | command_value;
  19. };
  20. class CommandBuilder {
  21. public:
  22. CommandBuilder(Vector<u32>& buffer, Protocol::VirGLCommand command, Protocol::ObjectType object_type)
  23. : m_buffer(buffer)
  24. , m_start_offset(buffer.size())
  25. , m_command(command)
  26. , m_object_type(object_type)
  27. {
  28. m_buffer.append(0);
  29. }
  30. void appendu32(u32 value)
  31. {
  32. VERIFY(!m_finalized);
  33. m_buffer.append(value);
  34. }
  35. void appendf32(float value)
  36. {
  37. VERIFY(!m_finalized);
  38. m_buffer.append(bit_cast<u32>(value));
  39. }
  40. void appendf64(double value)
  41. {
  42. VERIFY(!m_finalized);
  43. m_buffer.append(0);
  44. m_buffer.append(0);
  45. auto* depth = reinterpret_cast<u64*>(&m_buffer[m_buffer.size() - 2]);
  46. *depth = bit_cast<u64>(value);
  47. }
  48. void append_string_null_padded(StringView string)
  49. {
  50. VERIFY(!m_finalized);
  51. // Remember to have at least one null terminator byte
  52. auto length = string.length() + 1;
  53. auto num_required_words = (length + sizeof(u32) - 1) / sizeof(u32);
  54. m_buffer.resize(m_buffer.size() + num_required_words);
  55. char* dest = reinterpret_cast<char*>(&m_buffer[m_buffer.size() - num_required_words]);
  56. memcpy(dest, string.characters_without_null_termination(), string.length());
  57. // Pad end with null bytes
  58. memset(&dest[string.length()], 0, 4 * num_required_words - string.length());
  59. }
  60. void finalize()
  61. {
  62. if (!m_finalized) {
  63. m_finalized = true;
  64. size_t num_elems = m_buffer.size() - m_start_offset - 1;
  65. VERIFY(num_elems <= NumericLimits<u16>::max());
  66. m_buffer[m_start_offset] = encode_command(static_cast<u16>(num_elems), m_object_type, m_command);
  67. }
  68. }
  69. ~CommandBuilder()
  70. {
  71. if (!m_finalized)
  72. finalize();
  73. }
  74. private:
  75. Vector<u32>& m_buffer;
  76. size_t m_start_offset;
  77. Protocol::VirGLCommand m_command;
  78. Protocol::ObjectType m_object_type;
  79. bool m_finalized { false };
  80. };
  81. void CommandBufferBuilder::append_set_tweaks(u32 id, u32 value)
  82. {
  83. CommandBuilder builder(m_buffer, Protocol::VirGLCommand::SET_TWEAKS, Protocol::ObjectType::NONE);
  84. builder.appendu32(id);
  85. builder.appendu32(value);
  86. }
  87. void CommandBufferBuilder::append_transfer3d(Protocol::ResourceID resource, size_t width, size_t height, size_t depth, size_t direction)
  88. {
  89. CommandBuilder builder(m_buffer, Protocol::VirGLCommand::TRANSFER3D, Protocol::ObjectType::NONE);
  90. builder.appendu32(resource.value()); // res_handle
  91. builder.appendu32(0); // level
  92. // FIXME: It is not clear what this magic 242 value does.
  93. // According to https://gitlab.freedesktop.org/virgl/virglrenderer/-/blob/master/src/vrend_decode.c#L1398 it is unused
  94. // But ccapitalK had to specifically set it to prevent rendering failures.
  95. builder.appendu32(242); // usage
  96. builder.appendu32(0); // stride
  97. builder.appendu32(0); // layer_stride
  98. builder.appendu32(0); // x
  99. builder.appendu32(0); // y
  100. builder.appendu32(0); // z
  101. builder.appendu32(width); // width
  102. builder.appendu32(height); // height
  103. builder.appendu32(depth); // depth
  104. builder.appendu32(0); // data_offset
  105. builder.appendu32(direction); // direction
  106. }
  107. void CommandBufferBuilder::append_end_transfers_3d()
  108. {
  109. CommandBuilder builder(m_buffer, Protocol::VirGLCommand::END_TRANSFERS, Protocol::ObjectType::NONE);
  110. }
  111. void CommandBufferBuilder::append_draw_vbo(Protocol::PipePrimitiveTypes primitive_type, u32 count)
  112. {
  113. CommandBuilder builder(m_buffer, Protocol::VirGLCommand::DRAW_VBO, Protocol::ObjectType::NONE);
  114. builder.appendu32(0); // start
  115. builder.appendu32(count); // count
  116. builder.appendu32(to_underlying(primitive_type)); // mode
  117. builder.appendu32(0); // indexed
  118. builder.appendu32(1); // instance_count
  119. builder.appendu32(0); // index_bias
  120. builder.appendu32(0); // start_instance
  121. builder.appendu32(0); // primitive_restart
  122. builder.appendu32(0); // restart_index
  123. builder.appendu32(0); // min_index
  124. builder.appendu32(0xffffffff); // max_index
  125. builder.appendu32(0); // cso
  126. }
  127. void CommandBufferBuilder::append_clear(float r, float g, float b, float a)
  128. {
  129. CommandBuilder builder(m_buffer, Protocol::VirGLCommand::CLEAR, Protocol::ObjectType::NONE);
  130. Protocol::ClearType clear_flags {};
  131. clear_flags.flags.depth = 1;
  132. clear_flags.flags.color0 = 1;
  133. builder.appendu32(clear_flags.value);
  134. builder.appendf32(r);
  135. builder.appendf32(g);
  136. builder.appendf32(b);
  137. builder.appendf32(a);
  138. builder.appendf64(1.0);
  139. builder.appendu32(0);
  140. }
  141. void CommandBufferBuilder::append_clear(double depth)
  142. {
  143. CommandBuilder builder(m_buffer, Protocol::VirGLCommand::CLEAR, Protocol::ObjectType::NONE);
  144. Protocol::ClearType clear_flags {};
  145. clear_flags.flags.depth = 1;
  146. builder.appendu32(clear_flags.value);
  147. builder.appendf32(0);
  148. builder.appendf32(0);
  149. builder.appendf32(0);
  150. builder.appendf32(0);
  151. builder.appendf64(depth);
  152. builder.appendu32(0);
  153. }
  154. void CommandBufferBuilder::append_set_vertex_buffers(u32 stride, u32 offset, Protocol::ResourceID resource)
  155. {
  156. CommandBuilder builder(m_buffer, Protocol::VirGLCommand::SET_VERTEX_BUFFERS, Protocol::ObjectType::NONE);
  157. builder.appendu32(stride);
  158. builder.appendu32(offset);
  159. builder.appendu32(resource.value());
  160. }
  161. void CommandBufferBuilder::append_create_blend(Protocol::ObjectHandle handle)
  162. {
  163. CommandBuilder builder(m_buffer, Protocol::VirGLCommand::CREATE_OBJECT, Protocol::ObjectType::BLEND);
  164. builder.appendu32(handle.value());
  165. builder.appendu32(4); // Enable dither flag, and nothing else
  166. builder.appendu32(0);
  167. builder.appendu32(0x78000000); // Enable all bits of color mask for color buffer 0, and nothing else
  168. for (size_t i = 1; i < 8; ++i) {
  169. builder.appendu32(0); // Explicitly disable all flags for other color buffers
  170. }
  171. }
  172. void CommandBufferBuilder::append_bind_blend(Protocol::ObjectHandle handle)
  173. {
  174. CommandBuilder builder(m_buffer, Protocol::VirGLCommand::BIND_OBJECT, Protocol::ObjectType::BLEND);
  175. builder.appendu32(handle.value()); // VIRGL_OBJ_BIND_HANDLE
  176. }
  177. void CommandBufferBuilder::append_create_vertex_elements(Protocol::ObjectHandle handle)
  178. {
  179. CommandBuilder builder(m_buffer, Protocol::VirGLCommand::CREATE_OBJECT, Protocol::ObjectType::VERTEX_ELEMENTS);
  180. builder.appendu32(handle.value());
  181. builder.appendu32(12); // src_offset_0
  182. builder.appendu32(0); // instance_divisor_0
  183. builder.appendu32(0); // vertex_buffer_index_0
  184. builder.appendu32(30); // src_format_0 (PIPE_FORMAT_R32G32B32_FLOAT = 30)
  185. builder.appendu32(0); // src_offset_1
  186. builder.appendu32(0); // instance_divisor_1
  187. builder.appendu32(0); // vertex_buffer_index_1
  188. builder.appendu32(30); // src_format_1 (PIPE_FORMAT_R32G32B32_FLOAT = 30)
  189. }
  190. void CommandBufferBuilder::append_bind_vertex_elements(Protocol::ObjectHandle handle)
  191. {
  192. CommandBuilder builder(m_buffer, Protocol::VirGLCommand::BIND_OBJECT, Protocol::ObjectType::VERTEX_ELEMENTS);
  193. builder.appendu32(handle.value()); // VIRGL_OBJ_BIND_HANDLE
  194. }
  195. void CommandBufferBuilder::append_create_surface(Protocol::ResourceID drawtarget_resource, Protocol::ObjectHandle drawtarget_handle, Protocol::TextureFormat format)
  196. {
  197. CommandBuilder builder(m_buffer, Protocol::VirGLCommand::CREATE_OBJECT, Protocol::ObjectType::SURFACE);
  198. builder.appendu32(drawtarget_handle.value());
  199. builder.appendu32(drawtarget_resource.value());
  200. builder.appendu32(to_underlying(format));
  201. builder.appendu32(0); // First element / Texture Level
  202. builder.appendu32(0); // Last element / Texture Element
  203. }
  204. void CommandBufferBuilder::append_set_framebuffer_state(Protocol::ObjectHandle drawtarget, Protocol::ObjectHandle depthbuffer)
  205. {
  206. CommandBuilder builder(m_buffer, Protocol::VirGLCommand::SET_FRAMEBUFFER_STATE, Protocol::ObjectType::NONE);
  207. builder.appendu32(1); // nr_cbufs
  208. builder.appendu32(depthbuffer.value()); // zsurf_handle
  209. builder.appendu32(drawtarget.value()); // surf_handle
  210. }
  211. void CommandBufferBuilder::append_viewport(Gfx::IntSize size)
  212. {
  213. CommandBuilder builder(m_buffer, Protocol::VirGLCommand::SET_VIEWPORT_STATE, Protocol::ObjectType::NONE);
  214. builder.appendu32(0);
  215. builder.appendf32(size.width() / 2); // scale_x
  216. builder.appendf32(size.height() / 2); // scale_y (flipped, due to VirGL being different from our coordinate space)
  217. builder.appendf32(0.5f); // scale_z
  218. builder.appendf32(size.width() / 2); // translate_x
  219. builder.appendf32(size.height() / 2); // translate_y
  220. builder.appendf32(0.5f); // translate_z
  221. }
  222. void CommandBufferBuilder::append_set_framebuffer_state_no_attach(Gfx::IntSize size)
  223. {
  224. VERIFY(size.width() <= NumericLimits<u16>::max());
  225. VERIFY(size.height() <= NumericLimits<u16>::max());
  226. CommandBuilder builder(m_buffer, Protocol::VirGLCommand::SET_FRAMEBUFFER_STATE_NO_ATTACH, Protocol::ObjectType::NONE);
  227. u16 samples = 0;
  228. u16 layers = 0;
  229. builder.appendu32((size.height() << 16) | size.width());
  230. builder.appendu32((samples << 16) | layers);
  231. }
  232. void CommandBufferBuilder::append_set_constant_buffer(Vector<float> const& constant_buffer)
  233. {
  234. CommandBuilder builder(m_buffer, Protocol::VirGLCommand::SET_CONSTANT_BUFFER, Protocol::ObjectType::NONE);
  235. builder.appendu32(to_underlying(Gallium::ShaderType::SHADER_VERTEX));
  236. builder.appendu32(0); // index (currently unused according to virglrenderer source code)
  237. for (auto v : constant_buffer) {
  238. builder.appendf32(v);
  239. }
  240. }
  241. void CommandBufferBuilder::append_create_shader(Protocol::ObjectHandle handle, Gallium::ShaderType shader_type, StringView shader_data)
  242. {
  243. size_t shader_len = shader_data.length() + 1; // Need to remember to copy null terminator as well if needed
  244. CommandBuilder builder(m_buffer, Protocol::VirGLCommand::CREATE_OBJECT, Protocol::ObjectType::SHADER);
  245. builder.appendu32(handle.value()); // VIRGL_OBJ_CREATE_HANDLE
  246. builder.appendu32(to_underlying(shader_type));
  247. builder.appendu32(0); // VIRGL_OBJ_SHADER_OFFSET
  248. builder.appendu32(shader_len);
  249. builder.appendu32(0); // VIRGL_OBJ_SHADER_NUM_TOKENS
  250. builder.append_string_null_padded(shader_data);
  251. }
  252. void CommandBufferBuilder::append_bind_shader(Protocol::ObjectHandle handle, Gallium::ShaderType shader_type)
  253. {
  254. CommandBuilder builder(m_buffer, Protocol::VirGLCommand::BIND_SHADER, Protocol::ObjectType::NONE);
  255. builder.appendu32(handle.value()); // VIRGL_OBJ_BIND_HANDLE
  256. builder.appendu32(to_underlying(shader_type));
  257. }
  258. void CommandBufferBuilder::append_create_rasterizer(Protocol::ObjectHandle handle)
  259. {
  260. CommandBuilder builder(m_buffer, Protocol::VirGLCommand::CREATE_OBJECT, Protocol::ObjectType::RASTERIZER);
  261. builder.appendu32(handle.value()); // Handle
  262. builder.appendu32(0x00000002); // S0 (bitfield of state bits)
  263. builder.appendf32(1.0); // Point size
  264. builder.appendu32(0); // Sprite coord enable
  265. builder.appendu32(0x00000000); // S3 (bitfield of state bits)
  266. builder.appendf32(0.1); // Line width
  267. builder.appendf32(0.0); // Offset units
  268. builder.appendf32(0.0); // offset scale
  269. builder.appendf32(0.0); // Offset clamp
  270. }
  271. void CommandBufferBuilder::append_bind_rasterizer(Protocol::ObjectHandle handle)
  272. {
  273. CommandBuilder builder(m_buffer, Protocol::VirGLCommand::BIND_OBJECT, Protocol::ObjectType::RASTERIZER);
  274. builder.appendu32(handle.value()); // VIRGL_OBJ_BIND_HANDLE
  275. }
  276. void CommandBufferBuilder::append_create_dsa(Protocol::ObjectHandle handle)
  277. {
  278. CommandBuilder builder(m_buffer, Protocol::VirGLCommand::CREATE_OBJECT, Protocol::ObjectType::DSA);
  279. builder.appendu32(handle.value()); // Handle
  280. builder.appendu32(0x00000007); // S0 (bitset: (v >> 0) & 1 = depth.enabled, (v >> 1) & 1 = depth.writemask, (v >> 2) & 7 = depth.func)
  281. builder.appendu32(0x00000000); // S1 (bitset for 1st stencil buffer)
  282. builder.appendu32(0x00000000); // S2 (bitset for 2nd stencil buffer)
  283. builder.appendf32(1.0); // Alpha Ref
  284. }
  285. void CommandBufferBuilder::append_bind_dsa(Protocol::ObjectHandle handle)
  286. {
  287. CommandBuilder builder(m_buffer, Protocol::VirGLCommand::BIND_OBJECT, Protocol::ObjectType::DSA);
  288. builder.appendu32(handle.value()); // VIRGL_OBJ_BIND_HANDLE
  289. }
  290. }