• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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