1 /**************************************************************************
2 *
3 * Copyright © 2022 Intel Corporation
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 **************************************************************************/
25
26 #include "compiler/glsl/astc_glsl.h"
27 #include "compiler/glsl/bc1_glsl.h"
28 #include "compiler/glsl/bc4_glsl.h"
29 #include "compiler/glsl/cross_platform_settings_piece_all.h"
30 #include "compiler/glsl/etc2_rgba_stitch_glsl.h"
31
32 #include "main/context.h"
33 #include "main/shaderapi.h"
34 #include "main/shaderobj.h"
35 #include "main/texcompress_astc.h"
36 #include "util/texcompress_astc_luts_wrap.h"
37 #include "main/uniforms.h"
38
39 #include "state_tracker/st_atom_constbuf.h"
40 #include "state_tracker/st_bc1_tables.h"
41 #include "state_tracker/st_context.h"
42 #include "state_tracker/st_program.h"
43 #include "state_tracker/st_texcompress_compute.h"
44 #include "state_tracker/st_texture.h"
45
46 #include "util/u_hash_table.h"
47 #include "util/u_string.h"
48
49 enum compute_program_id {
50 COMPUTE_PROGRAM_BC1,
51 COMPUTE_PROGRAM_BC4,
52 COMPUTE_PROGRAM_STITCH,
53 COMPUTE_PROGRAM_ASTC_4x4,
54 COMPUTE_PROGRAM_ASTC_5x4,
55 COMPUTE_PROGRAM_ASTC_5x5,
56 COMPUTE_PROGRAM_ASTC_6x5,
57 COMPUTE_PROGRAM_ASTC_6x6,
58 COMPUTE_PROGRAM_ASTC_8x5,
59 COMPUTE_PROGRAM_ASTC_8x6,
60 COMPUTE_PROGRAM_ASTC_8x8,
61 COMPUTE_PROGRAM_ASTC_10x5,
62 COMPUTE_PROGRAM_ASTC_10x6,
63 COMPUTE_PROGRAM_ASTC_10x8,
64 COMPUTE_PROGRAM_ASTC_10x10,
65 COMPUTE_PROGRAM_ASTC_12x10,
66 COMPUTE_PROGRAM_ASTC_12x12,
67 COMPUTE_PROGRAM_COUNT
68 };
69
70 static struct gl_program * PRINTFLIKE(3, 4)
get_compute_program(struct st_context * st,enum compute_program_id prog_id,const char * source_fmt,...)71 get_compute_program(struct st_context *st,
72 enum compute_program_id prog_id,
73 const char *source_fmt, ...)
74 {
75 /* Try to get the program from the cache. */
76 assert(prog_id < COMPUTE_PROGRAM_COUNT);
77 if (st->texcompress_compute.progs[prog_id])
78 return st->texcompress_compute.progs[prog_id];
79
80 /* Cache miss. Create the final source string. */
81 char *source_str;
82 va_list ap;
83 va_start(ap, source_fmt);
84 int num_printed_bytes = vasprintf(&source_str, source_fmt, ap);
85 va_end(ap);
86 if (num_printed_bytes == -1)
87 return NULL;
88
89 /* Compile and link the shader. Then, destroy the shader string. */
90 const char *strings[] = { source_str };
91 GLuint program =
92 _mesa_CreateShaderProgramv_impl(st->ctx, GL_COMPUTE_SHADER, 1, strings);
93 free(source_str);
94
95 struct gl_shader_program *shProg =
96 _mesa_lookup_shader_program(st->ctx, program);
97 if (!shProg)
98 return NULL;
99
100 if (shProg->data->LinkStatus == LINKING_FAILURE) {
101 fprintf(stderr, "Linking failed:\n%s\n", shProg->data->InfoLog);
102 _mesa_reference_shader_program(st->ctx, &shProg, NULL);
103 return NULL;
104 }
105
106 /* Cache the program and return it. */
107 return st->texcompress_compute.progs[prog_id] =
108 shProg->_LinkedShaders[MESA_SHADER_COMPUTE]->Program;
109 }
110
111 static struct pipe_resource *
create_bc1_endpoint_ssbo(struct pipe_context * pipe)112 create_bc1_endpoint_ssbo(struct pipe_context *pipe)
113 {
114 struct pipe_resource *buffer =
115 pipe_buffer_create(pipe->screen, PIPE_BIND_SHADER_BUFFER,
116 PIPE_USAGE_IMMUTABLE, sizeof(float) *
117 (sizeof(stb__OMatch5) + sizeof(stb__OMatch6)));
118
119 if (!buffer)
120 return NULL;
121
122 struct pipe_transfer *transfer;
123 float (*buffer_map)[2] = pipe_buffer_map(pipe, buffer,
124 PIPE_MAP_WRITE |
125 PIPE_MAP_DISCARD_WHOLE_RESOURCE,
126 &transfer);
127 if (!buffer_map) {
128 pipe_resource_reference(&buffer, NULL);
129 return NULL;
130 }
131
132 for (int i = 0; i < 256; i++) {
133 for (int j = 0; j < 2; j++) {
134 buffer_map[i][j] = (float) stb__OMatch5[i][j];
135 buffer_map[i + 256][j] = (float) stb__OMatch6[i][j];
136 }
137 }
138
139 pipe_buffer_unmap(pipe, transfer);
140
141 return buffer;
142 }
143
144 static void
bind_compute_state(struct st_context * st,struct gl_program * prog,struct pipe_sampler_view ** sampler_views,const struct pipe_shader_buffer * shader_buffers,const struct pipe_image_view * image_views,bool cs_handle_from_prog,bool constbuf0_from_prog)145 bind_compute_state(struct st_context *st,
146 struct gl_program *prog,
147 struct pipe_sampler_view **sampler_views,
148 const struct pipe_shader_buffer *shader_buffers,
149 const struct pipe_image_view *image_views,
150 bool cs_handle_from_prog,
151 bool constbuf0_from_prog)
152 {
153 assert(prog->info.stage == PIPE_SHADER_COMPUTE);
154
155 /* Set compute states in the same order as defined in st_atom_list.h */
156
157 assert(prog->affected_states & ST_NEW_CS_STATE);
158 assert(st->shader_has_one_variant[PIPE_SHADER_COMPUTE]);
159 cso_set_compute_shader_handle(st->cso_context,
160 cs_handle_from_prog ?
161 prog->variants->driver_shader : NULL);
162
163 if (prog->affected_states & ST_NEW_CS_SAMPLER_VIEWS) {
164 st->pipe->set_sampler_views(st->pipe, prog->info.stage, 0,
165 prog->info.num_textures, 0, false,
166 sampler_views);
167 }
168
169 if (prog->affected_states & ST_NEW_CS_SAMPLERS) {
170 /* Programs seem to set this bit more often than needed. For example, if
171 * a program only uses texelFetch, this shouldn't be needed. Section
172 * "11.1.3.2 Texel Fetches", of the GL 4.6 spec says:
173 *
174 * Texel fetch proceeds similarly to the steps described for texture
175 * access in section 11.1.3.5, with the exception that none of the
176 * operations controlled by sampler object state are performed,
177 *
178 * We assume that the program is using texelFetch or doesn't care about
179 * this state for a similar reason.
180 *
181 * See https://gitlab.freedesktop.org/mesa/mesa/-/issues/8014.
182 */
183 }
184
185 if (prog->affected_states & ST_NEW_CS_CONSTANTS) {
186 st_upload_constants(st, constbuf0_from_prog ? prog : NULL,
187 prog->info.stage);
188 }
189
190 if (prog->affected_states & ST_NEW_CS_UBOS) {
191 unreachable("Uniform buffer objects not handled");
192 }
193
194 if (prog->affected_states & ST_NEW_CS_ATOMICS) {
195 unreachable("Atomic buffer objects not handled");
196 }
197
198 if (prog->affected_states & ST_NEW_CS_SSBOS) {
199 st->pipe->set_shader_buffers(st->pipe, prog->info.stage, 0,
200 prog->info.num_ssbos, shader_buffers,
201 prog->sh.ShaderStorageBlocksWriteAccess);
202 }
203
204 if (prog->affected_states & ST_NEW_CS_IMAGES) {
205 st->pipe->set_shader_images(st->pipe, prog->info.stage, 0,
206 prog->info.num_images, 0, image_views);
207 }
208 }
209
210 static void
dispatch_compute_state(struct st_context * st,struct gl_program * prog,struct pipe_sampler_view ** sampler_views,const struct pipe_shader_buffer * shader_buffers,const struct pipe_image_view * image_views,unsigned num_workgroups_x,unsigned num_workgroups_y,unsigned num_workgroups_z)211 dispatch_compute_state(struct st_context *st,
212 struct gl_program *prog,
213 struct pipe_sampler_view **sampler_views,
214 const struct pipe_shader_buffer *shader_buffers,
215 const struct pipe_image_view *image_views,
216 unsigned num_workgroups_x,
217 unsigned num_workgroups_y,
218 unsigned num_workgroups_z)
219 {
220 assert(prog->info.stage == PIPE_SHADER_COMPUTE);
221
222 /* Bind the state */
223 bind_compute_state(st, prog, sampler_views, shader_buffers, image_views,
224 true, true);
225
226 /* Launch the grid */
227 const struct pipe_grid_info info = {
228 .block[0] = prog->info.workgroup_size[0],
229 .block[1] = prog->info.workgroup_size[1],
230 .block[2] = prog->info.workgroup_size[2],
231 .grid[0] = num_workgroups_x,
232 .grid[1] = num_workgroups_y,
233 .grid[2] = num_workgroups_z,
234 };
235
236 st->pipe->launch_grid(st->pipe, &info);
237
238 /* Unbind the state */
239 bind_compute_state(st, prog, NULL, NULL, NULL, false, false);
240
241 /* If the previously used compute program was relying on any state that was
242 * trampled on by these state changes, dirty the relevant flags.
243 */
244 if (st->cp) {
245 st->ctx->NewDriverState |=
246 st->cp->affected_states & prog->affected_states;
247 }
248 }
249
250 static struct pipe_resource *
cs_encode_bc1(struct st_context * st,struct pipe_resource * rgba8_tex)251 cs_encode_bc1(struct st_context *st,
252 struct pipe_resource *rgba8_tex)
253 {
254 /* Create the required compute state */
255 struct gl_program *prog =
256 get_compute_program(st, COMPUTE_PROGRAM_BC1, bc1_source,
257 cross_platform_settings_piece_all_header);
258 if (!prog)
259 return NULL;
260
261 /* ... complete the program setup by defining the number of refinements to
262 * do on the created blocks. The program will attempt to create a more
263 * accurate encoding on each iteration. Doing at least one refinement
264 * provides a significant improvement in quality and is needed to give a
265 * result comparable to the CPU encoder (according to piglit tests).
266 * Additional refinements don't help as much.
267 */
268 const unsigned num_refinements = 1;
269 _mesa_uniform(0, 1, &num_refinements, st->ctx, prog->shader_program,
270 GLSL_TYPE_UINT, 1);
271
272 const struct pipe_sampler_view templ = {
273 .target = PIPE_TEXTURE_2D,
274 .format = PIPE_FORMAT_R8G8B8A8_UNORM,
275 .swizzle_r = PIPE_SWIZZLE_X,
276 .swizzle_g = PIPE_SWIZZLE_Y,
277 .swizzle_b = PIPE_SWIZZLE_Z,
278 .swizzle_a = PIPE_SWIZZLE_W,
279 };
280 struct pipe_sampler_view *rgba8_view =
281 st->pipe->create_sampler_view(st->pipe, rgba8_tex, &templ);
282 if (!rgba8_view)
283 return NULL;
284
285 const struct pipe_shader_buffer ssbo = {
286 .buffer = st->texcompress_compute.bc1_endpoint_buf,
287 .buffer_size = st->texcompress_compute.bc1_endpoint_buf->width0,
288 };
289
290 struct pipe_resource *bc1_tex =
291 st_texture_create(st, PIPE_TEXTURE_2D, PIPE_FORMAT_R32G32_UINT, 0,
292 DIV_ROUND_UP(rgba8_tex->width0, 4),
293 DIV_ROUND_UP(rgba8_tex->height0, 4), 1, 1, 0,
294 PIPE_BIND_SHADER_IMAGE |
295 PIPE_BIND_SAMPLER_VIEW, false);
296 if (!bc1_tex)
297 goto release_sampler_views;
298
299 const struct pipe_image_view image = {
300 .resource = bc1_tex,
301 .format = PIPE_FORMAT_R16G16B16A16_UINT,
302 .access = PIPE_IMAGE_ACCESS_WRITE,
303 .shader_access = PIPE_IMAGE_ACCESS_WRITE,
304 };
305
306 /* Dispatch the compute state */
307 dispatch_compute_state(st, prog, &rgba8_view, &ssbo, &image,
308 DIV_ROUND_UP(rgba8_tex->width0, 32),
309 DIV_ROUND_UP(rgba8_tex->height0, 32), 1);
310
311 release_sampler_views:
312 pipe_sampler_view_reference(&rgba8_view, NULL);
313
314 return bc1_tex;
315 }
316
317 static struct pipe_resource *
cs_encode_bc4(struct st_context * st,struct pipe_resource * rgba8_tex,enum pipe_swizzle component,bool use_snorm)318 cs_encode_bc4(struct st_context *st,
319 struct pipe_resource *rgba8_tex,
320 enum pipe_swizzle component, bool use_snorm)
321 {
322 /* Create the required compute state */
323 struct gl_program *prog =
324 get_compute_program(st, COMPUTE_PROGRAM_BC4, bc4_source,
325 cross_platform_settings_piece_all_header);
326 if (!prog)
327 return NULL;
328
329 /* ... complete the program setup by picking the channel to encode and
330 * whether to encode it as snorm. The shader doesn't actually support
331 * channel index 2. So, pick index 0 and rely on swizzling instead.
332 */
333 const unsigned params[] = { 0, use_snorm };
334 _mesa_uniform(0, 1, params, st->ctx, prog->shader_program,
335 GLSL_TYPE_UINT, 2);
336
337 const struct pipe_sampler_view templ = {
338 .target = PIPE_TEXTURE_2D,
339 .format = PIPE_FORMAT_R8G8B8A8_UNORM,
340 .swizzle_r = component,
341 .swizzle_g = PIPE_SWIZZLE_0,
342 .swizzle_b = PIPE_SWIZZLE_0,
343 .swizzle_a = PIPE_SWIZZLE_1,
344 };
345 struct pipe_sampler_view *rgba8_view =
346 st->pipe->create_sampler_view(st->pipe, rgba8_tex, &templ);
347 if (!rgba8_view)
348 return NULL;
349
350 struct pipe_resource *bc4_tex =
351 st_texture_create(st, PIPE_TEXTURE_2D, PIPE_FORMAT_R32G32_UINT, 0,
352 DIV_ROUND_UP(rgba8_tex->width0, 4),
353 DIV_ROUND_UP(rgba8_tex->height0, 4), 1, 1, 0,
354 PIPE_BIND_SHADER_IMAGE |
355 PIPE_BIND_SAMPLER_VIEW, false);
356 if (!bc4_tex)
357 goto release_sampler_views;
358
359 const struct pipe_image_view image = {
360 .resource = bc4_tex,
361 .format = PIPE_FORMAT_R16G16B16A16_UINT,
362 .access = PIPE_IMAGE_ACCESS_WRITE,
363 .shader_access = PIPE_IMAGE_ACCESS_WRITE,
364 };
365
366 /* Dispatch the compute state */
367 dispatch_compute_state(st, prog, &rgba8_view, NULL, &image, 1,
368 DIV_ROUND_UP(rgba8_tex->width0, 16),
369 DIV_ROUND_UP(rgba8_tex->height0, 16));
370
371 release_sampler_views:
372 pipe_sampler_view_reference(&rgba8_view, NULL);
373
374 return bc4_tex;
375 }
376
377 static struct pipe_resource *
cs_stitch_64bpb_textures(struct st_context * st,struct pipe_resource * tex_hi,struct pipe_resource * tex_lo)378 cs_stitch_64bpb_textures(struct st_context *st,
379 struct pipe_resource *tex_hi,
380 struct pipe_resource *tex_lo)
381 {
382 assert(util_format_get_blocksizebits(tex_hi->format) == 64);
383 assert(util_format_get_blocksizebits(tex_lo->format) == 64);
384 assert(tex_hi->width0 == tex_lo->width0);
385 assert(tex_hi->height0 == tex_lo->height0);
386
387 struct pipe_resource *stitched_tex = NULL;
388
389 /* Create the required compute state */
390 struct gl_program *prog =
391 get_compute_program(st, COMPUTE_PROGRAM_STITCH, etc2_rgba_stitch_source,
392 cross_platform_settings_piece_all_header);
393 if (!prog)
394 return NULL;
395
396 const struct pipe_sampler_view templ = {
397 .target = PIPE_TEXTURE_2D,
398 .format = PIPE_FORMAT_R32G32_UINT,
399 .swizzle_r = PIPE_SWIZZLE_X,
400 .swizzle_g = PIPE_SWIZZLE_Y,
401 .swizzle_b = PIPE_SWIZZLE_0,
402 .swizzle_a = PIPE_SWIZZLE_1,
403 };
404 struct pipe_sampler_view *rg32_views[2] = {
405 [0] = st->pipe->create_sampler_view(st->pipe, tex_hi, &templ),
406 [1] = st->pipe->create_sampler_view(st->pipe, tex_lo, &templ),
407 };
408 if (!rg32_views[0] || !rg32_views[1])
409 goto release_sampler_views;
410
411 stitched_tex =
412 st_texture_create(st, PIPE_TEXTURE_2D, PIPE_FORMAT_R32G32B32A32_UINT, 0,
413 tex_hi->width0,
414 tex_hi->height0, 1, 1, 0,
415 PIPE_BIND_SHADER_IMAGE |
416 PIPE_BIND_SAMPLER_VIEW, false);
417 if (!stitched_tex)
418 goto release_sampler_views;
419
420 const struct pipe_image_view image = {
421 .resource = stitched_tex,
422 .format = PIPE_FORMAT_R32G32B32A32_UINT,
423 .access = PIPE_IMAGE_ACCESS_WRITE,
424 .shader_access = PIPE_IMAGE_ACCESS_WRITE,
425 };
426
427 /* Dispatch the compute state */
428 dispatch_compute_state(st, prog, rg32_views, NULL, &image,
429 DIV_ROUND_UP(tex_hi->width0, 8),
430 DIV_ROUND_UP(tex_hi->height0, 8), 1);
431
432 release_sampler_views:
433 pipe_sampler_view_reference(&rg32_views[0], NULL);
434 pipe_sampler_view_reference(&rg32_views[1], NULL);
435
436 return stitched_tex;
437 }
438
439 static struct pipe_resource *
cs_encode_bc3(struct st_context * st,struct pipe_resource * rgba8_tex)440 cs_encode_bc3(struct st_context *st,
441 struct pipe_resource *rgba8_tex)
442 {
443 struct pipe_resource *bc3_tex = NULL;
444
445 /* Encode RGB channels as BC1. */
446 struct pipe_resource *bc1_tex = cs_encode_bc1(st, rgba8_tex);
447 if (!bc1_tex)
448 return NULL;
449
450 /* Encode alpha channels as BC4. */
451 struct pipe_resource *bc4_tex =
452 cs_encode_bc4(st, rgba8_tex, PIPE_SWIZZLE_W, false);
453 if (!bc4_tex)
454 goto release_textures;
455
456 st->pipe->memory_barrier(st->pipe, PIPE_BARRIER_TEXTURE);
457
458 /* Combine BC1 and BC4 to create BC3. */
459 bc3_tex = cs_stitch_64bpb_textures(st, bc1_tex, bc4_tex);
460 if (!bc3_tex)
461 goto release_textures;
462
463 release_textures:
464 pipe_resource_reference(&bc1_tex, NULL);
465 pipe_resource_reference(&bc4_tex, NULL);
466
467 return bc3_tex;
468 }
469
470 static struct pipe_resource *
sw_decode_astc(struct st_context * st,uint8_t * astc_data,unsigned astc_stride,mesa_format astc_format,unsigned width_px,unsigned height_px)471 sw_decode_astc(struct st_context *st,
472 uint8_t *astc_data,
473 unsigned astc_stride,
474 mesa_format astc_format,
475 unsigned width_px, unsigned height_px)
476 {
477 /* Create the destination */
478 struct pipe_resource *rgba8_tex =
479 st_texture_create(st, PIPE_TEXTURE_2D, PIPE_FORMAT_R8G8B8A8_UNORM, 0,
480 width_px, height_px, 1, 1, 0,
481 PIPE_BIND_SAMPLER_VIEW, false);
482 if (!rgba8_tex)
483 return NULL;
484
485 /* Temporarily map the destination and decode into the returned pointer */
486 struct pipe_transfer *rgba8_xfer;
487 void *rgba8_map = pipe_texture_map(st->pipe, rgba8_tex, 0, 0,
488 PIPE_MAP_WRITE, 0, 0,
489 width_px, height_px, &rgba8_xfer);
490 if (!rgba8_map) {
491 pipe_resource_reference(&rgba8_tex, NULL);
492 return NULL;
493 }
494
495 _mesa_unpack_astc_2d_ldr(rgba8_map, rgba8_xfer->stride,
496 astc_data, astc_stride,
497 width_px, height_px, astc_format);
498
499 pipe_texture_unmap(st->pipe, rgba8_xfer);
500
501 return rgba8_tex;
502 }
503
504 static struct pipe_sampler_view *
create_astc_cs_payload_view(struct st_context * st,uint8_t * data,unsigned stride,uint32_t width_el,uint32_t height_el)505 create_astc_cs_payload_view(struct st_context *st,
506 uint8_t *data, unsigned stride,
507 uint32_t width_el, uint32_t height_el)
508 {
509 const struct pipe_resource src_templ = {
510 .target = PIPE_TEXTURE_2D,
511 .format = PIPE_FORMAT_R32G32B32A32_UINT,
512 .bind = PIPE_BIND_SAMPLER_VIEW,
513 .usage = PIPE_USAGE_STAGING,
514 .width0 = width_el,
515 .height0 = height_el,
516 .depth0 = 1,
517 .array_size = 1,
518 };
519
520 struct pipe_resource *payload_res =
521 st->screen->resource_create(st->screen, &src_templ);
522
523 if (!payload_res)
524 return NULL;
525
526 struct pipe_box box;
527 u_box_origin_2d(width_el, height_el, &box);
528
529 st->pipe->texture_subdata(st->pipe, payload_res, 0, 0,
530 &box,
531 data,
532 stride,
533 0 /* unused */);
534
535 const struct pipe_sampler_view view_templ = {
536 .target = PIPE_TEXTURE_2D,
537 .format = payload_res->format,
538 .swizzle_r = PIPE_SWIZZLE_X,
539 .swizzle_g = PIPE_SWIZZLE_Y,
540 .swizzle_b = PIPE_SWIZZLE_Z,
541 .swizzle_a = PIPE_SWIZZLE_W,
542 };
543
544 struct pipe_sampler_view *view =
545 st->pipe->create_sampler_view(st->pipe, payload_res, &view_templ);
546
547 pipe_resource_reference(&payload_res, NULL);
548
549 return view;
550 }
551
552 static struct pipe_sampler_view *
get_astc_partition_table_view(struct st_context * st,unsigned block_w,unsigned block_h)553 get_astc_partition_table_view(struct st_context *st,
554 unsigned block_w,
555 unsigned block_h)
556 {
557 unsigned lut_width;
558 unsigned lut_height;
559 struct pipe_box ptable_box;
560 void *ptable_data =
561 _mesa_get_astc_decoder_partition_table(block_w, block_h, &lut_width, &lut_height);
562 u_box_origin_2d(lut_width, lut_height, &ptable_box);
563
564 struct pipe_sampler_view *view =
565 util_hash_table_get(st->texcompress_compute.astc_partition_tables,
566 ptable_data);
567
568 if (view)
569 return view;
570
571 struct pipe_resource *res =
572 st_texture_create(st, PIPE_TEXTURE_2D, PIPE_FORMAT_R8_UINT, 0,
573 ptable_box.width, ptable_box.height,
574 1, 1, 0,
575 PIPE_BIND_SAMPLER_VIEW, false);
576 if (!res)
577 return NULL;
578
579 st->pipe->texture_subdata(st->pipe, res, 0, 0,
580 &ptable_box,
581 ptable_data,
582 ptable_box.width,
583 0 /* unused */);
584
585 const struct pipe_sampler_view templ = {
586 .target = PIPE_TEXTURE_2D,
587 .format = res->format,
588 .swizzle_r = PIPE_SWIZZLE_X,
589 .swizzle_g = PIPE_SWIZZLE_Y,
590 .swizzle_b = PIPE_SWIZZLE_Z,
591 .swizzle_a = PIPE_SWIZZLE_W,
592 };
593
594 view = st->pipe->create_sampler_view(st->pipe, res, &templ);
595
596 pipe_resource_reference(&res, NULL);
597
598 if (view) {
599 _mesa_hash_table_insert(st->texcompress_compute.astc_partition_tables,
600 ptable_data, view);
601 ASSERTED const unsigned max_entries =
602 COMPUTE_PROGRAM_ASTC_12x12 - COMPUTE_PROGRAM_ASTC_4x4 + 1;
603 assert(_mesa_hash_table_num_entries(
604 st->texcompress_compute.astc_partition_tables) < max_entries);
605 }
606
607 return view;
608 }
609
610 static struct pipe_resource *
cs_decode_astc(struct st_context * st,uint8_t * astc_data,unsigned astc_stride,mesa_format astc_format,unsigned width_px,unsigned height_px)611 cs_decode_astc(struct st_context *st,
612 uint8_t *astc_data,
613 unsigned astc_stride,
614 mesa_format astc_format,
615 unsigned width_px, unsigned height_px)
616 {
617 const enum compute_program_id astc_id = COMPUTE_PROGRAM_ASTC_4x4 +
618 util_format_linear(astc_format) - PIPE_FORMAT_ASTC_4x4;
619
620 unsigned block_w, block_h;
621 _mesa_get_format_block_size(astc_format, &block_w, &block_h);
622
623 struct gl_program *prog =
624 get_compute_program(st, astc_id, astc_source, block_w, block_h);
625
626 if (!prog)
627 return NULL;
628
629 struct pipe_sampler_view *ptable_view =
630 get_astc_partition_table_view(st, block_w, block_h);
631
632 if (!ptable_view)
633 return NULL;
634
635 struct pipe_sampler_view *payload_view =
636 create_astc_cs_payload_view(st, astc_data, astc_stride,
637 DIV_ROUND_UP(width_px, block_w),
638 DIV_ROUND_UP(height_px, block_h));
639
640 if (!payload_view)
641 return NULL;
642
643 /* Create the destination */
644 struct pipe_resource *rgba8_tex =
645 st_texture_create(st, PIPE_TEXTURE_2D, PIPE_FORMAT_R8G8B8A8_UNORM, 0,
646 width_px, height_px, 1, 1, 0,
647 PIPE_BIND_SAMPLER_VIEW, false);
648
649 if (!rgba8_tex)
650 goto release_payload_view;
651
652 const struct pipe_image_view image = {
653 .resource = rgba8_tex,
654 .format = PIPE_FORMAT_R8G8B8A8_UINT,
655 .access = PIPE_IMAGE_ACCESS_WRITE,
656 .shader_access = PIPE_IMAGE_ACCESS_WRITE,
657 };
658
659 struct pipe_sampler_view *sampler_views[] = {
660 st->texcompress_compute.astc_luts[0],
661 st->texcompress_compute.astc_luts[1],
662 st->texcompress_compute.astc_luts[2],
663 st->texcompress_compute.astc_luts[3],
664 st->texcompress_compute.astc_luts[4],
665 ptable_view,
666 payload_view,
667 };
668
669 dispatch_compute_state(st, prog, sampler_views, NULL, &image,
670 DIV_ROUND_UP(payload_view->texture->width0, 2),
671 DIV_ROUND_UP(payload_view->texture->height0, 2),
672 1);
673
674 release_payload_view:
675 pipe_sampler_view_reference(&payload_view, NULL);
676
677 return rgba8_tex;
678 }
679
680 static struct pipe_sampler_view *
get_sampler_view_for_lut(struct pipe_context * pipe,const astc_decoder_lut * lut)681 get_sampler_view_for_lut(struct pipe_context *pipe,
682 const astc_decoder_lut *lut)
683 {
684 struct pipe_resource *res =
685 pipe_buffer_create_with_data(pipe,
686 PIPE_BIND_SAMPLER_VIEW,
687 PIPE_USAGE_DEFAULT,
688 lut->size_B,
689 lut->data);
690 if (!res)
691 return NULL;
692
693 const struct pipe_sampler_view templ = {
694 .format = lut->format,
695 .target = PIPE_BUFFER,
696 .swizzle_r = PIPE_SWIZZLE_X,
697 .swizzle_g = PIPE_SWIZZLE_Y,
698 .swizzle_b = PIPE_SWIZZLE_Z,
699 .swizzle_a = PIPE_SWIZZLE_W,
700 .u.buf.offset = 0,
701 .u.buf.size = lut->size_B,
702 };
703
704 struct pipe_sampler_view *view =
705 pipe->create_sampler_view(pipe, res, &templ);
706
707 pipe_resource_reference(&res, NULL);
708
709 return view;
710 }
711
712 /* Initializes required resources for Granite ASTC GPU decode.
713 *
714 * There are 5 texture buffer objects and one additional texture required.
715 * We initialize 5 tbo's here and a single texture later during runtime.
716 */
717 static bool
initialize_astc_decoder(struct st_context * st)718 initialize_astc_decoder(struct st_context *st)
719 {
720 astc_decoder_lut_holder astc_lut_holder;
721 _mesa_init_astc_decoder_luts(&astc_lut_holder);
722
723 const astc_decoder_lut *luts[] = {
724 &astc_lut_holder.color_endpoint,
725 &astc_lut_holder.color_endpoint_unquant,
726 &astc_lut_holder.weights,
727 &astc_lut_holder.weights_unquant,
728 &astc_lut_holder.trits_quints,
729 };
730
731 for (unsigned i = 0; i < ARRAY_SIZE(luts); i++) {
732 st->texcompress_compute.astc_luts[i] =
733 get_sampler_view_for_lut(st->pipe, luts[i]);
734 if (!st->texcompress_compute.astc_luts[i])
735 return false;
736 }
737
738 st->texcompress_compute.astc_partition_tables =
739 _mesa_pointer_hash_table_create(NULL);
740
741 if (!st->texcompress_compute.astc_partition_tables)
742 return false;
743
744 return true;
745 }
746
747 bool
st_init_texcompress_compute(struct st_context * st)748 st_init_texcompress_compute(struct st_context *st)
749 {
750 st->texcompress_compute.progs =
751 calloc(COMPUTE_PROGRAM_COUNT, sizeof(struct gl_program *));
752 if (!st->texcompress_compute.progs)
753 return false;
754
755 st->texcompress_compute.bc1_endpoint_buf =
756 create_bc1_endpoint_ssbo(st->pipe);
757 if (!st->texcompress_compute.bc1_endpoint_buf)
758 return false;
759
760 if (!initialize_astc_decoder(st))
761 return false;
762
763 return true;
764 }
765
766 static void
destroy_astc_decoder(struct st_context * st)767 destroy_astc_decoder(struct st_context *st)
768 {
769 for (unsigned i = 0; i < ARRAY_SIZE(st->texcompress_compute.astc_luts); i++)
770 pipe_sampler_view_reference(&st->texcompress_compute.astc_luts[i], NULL);
771
772 if (st->texcompress_compute.astc_partition_tables) {
773 hash_table_foreach(st->texcompress_compute.astc_partition_tables,
774 entry) {
775 pipe_sampler_view_reference(
776 (struct pipe_sampler_view **)&entry->data, NULL);
777 }
778 }
779
780 _mesa_hash_table_destroy(st->texcompress_compute.astc_partition_tables,
781 NULL);
782 }
783
784 void
st_destroy_texcompress_compute(struct st_context * st)785 st_destroy_texcompress_compute(struct st_context *st)
786 {
787 /* The programs in the array are part of the gl_context (in st->ctx).They
788 * are automatically destroyed when the context is destroyed (via
789 * _mesa_free_context_data -> ... -> free_shader_program_data_cb).
790 */
791 free(st->texcompress_compute.progs);
792
793 /* Destroy the SSBO used by the BC1 shader program. */
794 pipe_resource_reference(&st->texcompress_compute.bc1_endpoint_buf, NULL);
795
796 destroy_astc_decoder(st);
797 }
798
799 /* See st_texcompress_compute.h for more information. */
800 bool
st_compute_transcode_astc_to_dxt5(struct st_context * st,uint8_t * astc_data,unsigned astc_stride,mesa_format astc_format,struct pipe_resource * dxt5_tex,unsigned dxt5_level,unsigned dxt5_layer)801 st_compute_transcode_astc_to_dxt5(struct st_context *st,
802 uint8_t *astc_data,
803 unsigned astc_stride,
804 mesa_format astc_format,
805 struct pipe_resource *dxt5_tex,
806 unsigned dxt5_level,
807 unsigned dxt5_layer)
808 {
809 assert(_mesa_has_compute_shaders(st->ctx));
810 assert(_mesa_is_format_astc_2d(astc_format));
811 assert(dxt5_tex->format == PIPE_FORMAT_DXT5_RGBA ||
812 dxt5_tex->format == PIPE_FORMAT_DXT5_SRGBA);
813 assert(dxt5_level <= dxt5_tex->last_level);
814 assert(dxt5_layer <= util_max_layer(dxt5_tex, dxt5_level));
815
816 bool success = false;
817
818 /* Decode ASTC to RGBA8. */
819 struct pipe_resource *rgba8_tex =
820 cs_decode_astc(st, astc_data, astc_stride, astc_format,
821 u_minify(dxt5_tex->width0, dxt5_level),
822 u_minify(dxt5_tex->height0, dxt5_level));
823 if (!rgba8_tex)
824 return false;
825
826 st->pipe->memory_barrier(st->pipe, PIPE_BARRIER_TEXTURE);
827
828 /* Encode RGBA8 to BC3. */
829 struct pipe_resource *bc3_tex = cs_encode_bc3(st, rgba8_tex);
830 if (!bc3_tex)
831 goto release_textures;
832
833 /* Upload the result. */
834 struct pipe_box src_box;
835 u_box_origin_2d(bc3_tex->width0, bc3_tex->height0, &src_box);
836 st->pipe->resource_copy_region(st->pipe, dxt5_tex, dxt5_level,
837 0, 0, dxt5_layer, bc3_tex, 0, &src_box);
838
839 success = true;
840
841 release_textures:
842 pipe_resource_reference(&rgba8_tex, NULL);
843 pipe_resource_reference(&bc3_tex, NULL);
844
845 return success;
846 }
847