CommandBufferBuilder.cpp 12 KB

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