1 /*
2  * Copyright © 2022 Collabora Ltd
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 #include "vk_meta_private.h"
25 
26 #include "vk_command_buffer.h"
27 #include "vk_command_pool.h"
28 #include "vk_device.h"
29 
30 #include "nir_builder.h"
31 
32 const VkPipelineVertexInputStateCreateInfo vk_meta_draw_rects_vi_state = {
33    .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
34    .vertexBindingDescriptionCount = 1,
35    .pVertexBindingDescriptions = &(const VkVertexInputBindingDescription) {
36       .binding = 0,
37       .stride = 4 * sizeof(uint32_t),
38       .inputRate = VK_VERTEX_INPUT_RATE_VERTEX,
39    },
40    .vertexAttributeDescriptionCount = 1,
41    .pVertexAttributeDescriptions = &(const VkVertexInputAttributeDescription) {
42       .location = 0,
43       .binding = 0,
44       .format = VK_FORMAT_R32G32B32A32_UINT,
45       .offset = 0,
46    },
47 };
48 
49 const VkPipelineInputAssemblyStateCreateInfo vk_meta_draw_rects_ia_state = {
50    .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
51    .topology = VK_PRIMITIVE_TOPOLOGY_META_RECT_LIST_MESA,
52    .primitiveRestartEnable = VK_FALSE,
53 };
54 
55 const VkPipelineViewportStateCreateInfo vk_meta_draw_rects_vs_state = {
56    .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
57    .viewportCount = 1,
58    .scissorCount = 1,
59 };
60 
61 nir_shader *
vk_meta_draw_rects_vs_nir(struct vk_meta_device * device,bool use_gs)62 vk_meta_draw_rects_vs_nir(struct vk_meta_device *device, bool use_gs)
63 {
64    nir_builder build = nir_builder_init_simple_shader(MESA_SHADER_VERTEX, NULL,
65                                                       "vk-meta-draw-rects-vs");
66    nir_builder *b = &build;
67 
68    nir_variable *in = nir_variable_create(b->shader, nir_var_shader_in,
69                                           glsl_uvec4_type(), "vtx_in");
70    in->data.location = VERT_ATTRIB_GENERIC0;
71 
72    nir_variable *pos =
73       nir_variable_create(b->shader, nir_var_shader_out, glsl_vec4_type(),
74                           use_gs ? "pos_out" : "gl_Position");
75    pos->data.location = use_gs ? VARYING_SLOT_VAR0 : VARYING_SLOT_POS;
76 
77    nir_variable *layer =
78       nir_variable_create(b->shader, nir_var_shader_out, glsl_int_type(),
79                           use_gs ? "layer_out" : "gl_Layer");
80    layer->data.location = use_gs ? VARYING_SLOT_VAR1 : VARYING_SLOT_LAYER;
81 
82    nir_def *vtx = nir_load_var(b, in);
83    nir_store_var(b, pos, nir_vec4(b, nir_channel(b, vtx, 0),
84                                      nir_channel(b, vtx, 1),
85                                      nir_channel(b, vtx, 2),
86                                      nir_imm_float(b, 1)),
87                  0xf);
88 
89    nir_store_var(b, layer, nir_iadd(b, nir_load_instance_id(b),
90                                        nir_channel(b, vtx, 3)),
91                  0x1);
92 
93    return b->shader;
94 }
95 
96 nir_shader *
vk_meta_draw_rects_gs_nir(struct vk_meta_device * device)97 vk_meta_draw_rects_gs_nir(struct vk_meta_device *device)
98 {
99    nir_builder build =
100       nir_builder_init_simple_shader(MESA_SHADER_GEOMETRY, NULL,
101                                      "vk-meta-draw-rects-gs");
102    nir_builder *b = &build;
103 
104    nir_variable *pos_in =
105       nir_variable_create(b->shader, nir_var_shader_in,
106                           glsl_array_type(glsl_vec4_type(), 3, 0), "pos_in");
107    pos_in->data.location = VARYING_SLOT_VAR0;
108 
109    nir_variable *layer_in =
110       nir_variable_create(b->shader, nir_var_shader_in,
111                           glsl_array_type(glsl_int_type(), 3, 0), "layer_in");
112    layer_in->data.location = VARYING_SLOT_VAR1;
113 
114    nir_variable *pos_out =
115       nir_variable_create(b->shader, nir_var_shader_out,
116                           glsl_vec4_type(), "gl_Position");
117    pos_out->data.location = VARYING_SLOT_POS;
118 
119    nir_variable *layer_out =
120       nir_variable_create(b->shader, nir_var_shader_out,
121                           glsl_int_type(), "gl_Layer");
122    layer_out->data.location = VARYING_SLOT_LAYER;
123 
124    for (unsigned i = 0; i < 3; i++) {
125       nir_deref_instr *pos_in_deref =
126          nir_build_deref_array_imm(b, nir_build_deref_var(b, pos_in), i);
127       nir_deref_instr *layer_in_deref =
128          nir_build_deref_array_imm(b, nir_build_deref_var(b, layer_in), i);
129 
130       nir_store_var(b, pos_out, nir_load_deref(b, pos_in_deref), 0xf);
131       nir_store_var(b, layer_out, nir_load_deref(b, layer_in_deref), 1);
132       nir_emit_vertex(b);
133    }
134 
135    nir_end_primitive(b);
136 
137    struct shader_info *info = &build.shader->info;
138    info->gs.input_primitive = MESA_PRIM_TRIANGLES;
139    info->gs.output_primitive = MESA_PRIM_TRIANGLE_STRIP;
140    info->gs.vertices_in = 3;
141    info->gs.vertices_out = 3;
142    info->gs.invocations = 1;
143    info->gs.active_stream_mask = 1;
144 
145    return b->shader;
146 }
147 
148 struct vertex {
149    float x, y, z;
150    uint32_t layer;
151 };
152 
153 static void
setup_viewport_scissor(struct vk_command_buffer * cmd,uint32_t rect_count,const struct vk_meta_rect * rects,float * x_scale,float * y_scale)154 setup_viewport_scissor(struct vk_command_buffer *cmd,
155                        uint32_t rect_count,
156                        const struct vk_meta_rect *rects,
157                        float *x_scale, float *y_scale)
158 {
159    const struct vk_device_dispatch_table *disp =
160       &cmd->base.device->dispatch_table;
161    VkCommandBuffer _cmd = vk_command_buffer_to_handle(cmd);
162 
163    assert(rects[0].x0 < rects[0].x1 && rects[0].y0 < rects[0].y1);
164    uint32_t xbits = rects[0].x1 - 1, ybits = rects[0].y1 - 1;
165    float zmin = rects[0].z, zmax = rects[0].z;
166    for (uint32_t r = 1; r < rect_count; r++) {
167       assert(rects[r].x0 < rects[r].x1 && rects[r].y0 < rects[r].y1);
168       xbits |= rects[r].x1 - 1;
169       ybits |= rects[r].y1 - 1;
170       zmin = fminf(zmin, rects[r].z);
171       zmax = fminf(zmax, rects[r].z);
172    }
173 
174    /* Annoyingly, we don't actually know the render area.  We assume that all
175     * our rects are inside the render area.  We further assume the maximum
176     * image and/or viewport size is a power of two.  This means we can round
177     * up to a power of two without going outside any maximums.  Using a power
178     * of two will ensure we don't lose precision when scaling coordinates.
179     */
180    int xmax_log2 = 1 + util_logbase2(xbits);
181    int ymax_log2 = 1 + util_logbase2(ybits);
182 
183    assert(xmax_log2 >= 0 && xmax_log2 <= 31);
184    assert(ymax_log2 >= 0 && ymax_log2 <= 31);
185 
186    /* We don't care about precise bounds on Z, only that it's inside [0, 1] if
187     * the implementaiton only supports [0, 1].
188     */
189    if (zmin >= 0.0f && zmax <= 1.0f) {
190       zmin = 0.0f;
191       zmax = 1.0f;
192    }
193 
194    VkViewport viewport = {
195       .x = 0,
196       .y = 0,
197       .width = ldexpf(1.0, xmax_log2),
198       .height = ldexpf(1.0, ymax_log2),
199       .minDepth = zmin,
200       .maxDepth = zmax,
201    };
202    disp->CmdSetViewport(_cmd, 0, 1, &viewport);
203 
204    VkRect2D scissor = {
205       .offset = { 0, 0 },
206       .extent = { 1u << xmax_log2, 1u << ymax_log2 },
207    };
208    disp->CmdSetScissor(_cmd, 0, 1, &scissor);
209 
210    /* Scaling factors */
211    *x_scale = ldexpf(2.0, -xmax_log2);
212    *y_scale = ldexpf(2.0, -ymax_log2);
213 }
214 
215 static const uint32_t rect_vb_size_B = 6 * 4 * sizeof(float);
216 
217 static VkResult
create_vertex_buffer(struct vk_command_buffer * cmd,struct vk_meta_device * meta,float x_scale,float y_scale,uint32_t rect_count,const struct vk_meta_rect * rects,VkBuffer * buffer_out)218 create_vertex_buffer(struct vk_command_buffer *cmd,
219                      struct vk_meta_device *meta,
220                      float x_scale, float y_scale,
221                      uint32_t rect_count,
222                      const struct vk_meta_rect *rects,
223                      VkBuffer *buffer_out)
224 {
225    VkResult result;
226 
227    const VkBufferCreateInfo vtx_buffer_info = {
228       .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
229       .size = rect_count * rect_vb_size_B,
230       .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
231       .queueFamilyIndexCount = 1,
232       .pQueueFamilyIndices = &cmd->pool->queue_family_index,
233    };
234 
235    result = vk_meta_create_buffer(cmd, meta, &vtx_buffer_info, buffer_out);
236    if (unlikely(result != VK_SUCCESS))
237       return result;
238 
239    void *map;
240    result = meta->cmd_bind_map_buffer(cmd, meta, *buffer_out, &map);
241    if (unlikely(result != VK_SUCCESS))
242       return result;
243 
244    for (uint32_t r = 0; r < rect_count; r++) {
245       float x0 = rects[r].x0 * x_scale - 1.0f;
246       float y0 = rects[r].y0 * y_scale - 1.0f;
247       float x1 = rects[r].x1 * x_scale - 1.0f;
248       float y1 = rects[r].y1 * y_scale - 1.0f;
249       float z = rects[r].z;
250       uint32_t w = rects[r].layer;
251 
252       struct vertex rect_vb_data[6] = {
253          { x0, y1, z, w },
254          { x0, y0, z, w },
255          { x1, y1, z, w },
256 
257          { x1, y0, z, w },
258          { x1, y1, z, w },
259          { x0, y0, z, w },
260       };
261       assert(sizeof(rect_vb_data) == rect_vb_size_B);
262       memcpy((char *)map + r * rect_vb_size_B, rect_vb_data, rect_vb_size_B);
263    }
264 
265    return VK_SUCCESS;
266 }
267 
268 void
vk_meta_draw_volume(struct vk_command_buffer * cmd,struct vk_meta_device * meta,const struct vk_meta_rect * rect,uint32_t layer_count)269 vk_meta_draw_volume(struct vk_command_buffer *cmd,
270                     struct vk_meta_device *meta,
271                     const struct vk_meta_rect *rect,
272                     uint32_t layer_count)
273 {
274    const struct vk_device_dispatch_table *disp =
275       &cmd->base.device->dispatch_table;
276    VkCommandBuffer _cmd = vk_command_buffer_to_handle(cmd);
277 
278    float x_scale, y_scale;
279    setup_viewport_scissor(cmd, 1, rect, &x_scale, &y_scale);
280 
281    VkBuffer vtx_buffer;
282    VkResult result = create_vertex_buffer(cmd, meta, x_scale, y_scale,
283                                           1, rect, &vtx_buffer);
284    if (unlikely(result != VK_SUCCESS)) {
285       /* TODO: Report error */
286       return;
287    }
288 
289    const VkDeviceSize zero = 0;
290    disp->CmdBindVertexBuffers(_cmd, 0, 1, &vtx_buffer, &zero);
291 
292    disp->CmdDraw(_cmd, 6, layer_count, 0, 0);
293 }
294 
295 void
vk_meta_draw_rects(struct vk_command_buffer * cmd,struct vk_meta_device * meta,uint32_t rect_count,const struct vk_meta_rect * rects)296 vk_meta_draw_rects(struct vk_command_buffer *cmd,
297                    struct vk_meta_device *meta,
298                    uint32_t rect_count,
299                    const struct vk_meta_rect *rects)
300 {
301    const struct vk_device_dispatch_table *disp =
302       &cmd->base.device->dispatch_table;
303    VkCommandBuffer _cmd = vk_command_buffer_to_handle(cmd);
304 
305    /* Two triangles with VK_FORMAT_R16G16_UINT */
306    const uint32_t rect_vb_size_B = 6 * 3 * sizeof(float);
307    const uint32_t rects_per_draw =
308       meta->max_bind_map_buffer_size_B / rect_vb_size_B;
309 
310    if (rect_count == 0)
311       return;
312 
313    float x_scale, y_scale;
314    setup_viewport_scissor(cmd, rect_count, rects, &x_scale, &y_scale);
315 
316    uint32_t next_rect = 0;
317    while (next_rect < rect_count) {
318       const uint32_t count = MIN2(rects_per_draw, rect_count - next_rect);
319 
320       VkBuffer vtx_buffer;
321       VkResult result = create_vertex_buffer(cmd, meta, x_scale, y_scale,
322                                              count, &rects[next_rect],
323                                              &vtx_buffer);
324       if (unlikely(result != VK_SUCCESS)) {
325          /* TODO: Report error */
326          return;
327       }
328 
329       const VkDeviceSize zero = 0;
330       disp->CmdBindVertexBuffers(_cmd, 0, 1, &vtx_buffer, &zero);
331 
332       disp->CmdDraw(_cmd, 6 * count, 1, 0, 0);
333 
334       next_rect += count;
335    }
336    assert(next_rect == rect_count);
337 }
338