1/*
2 * Copyright © 2014-2015 Broadcom
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 "util/u_pack_color.h"
25#include "util/format_srgb.h"
26
27#include "vc4_context.h"
28#include "vc4_qir.h"
29
30static void
31write_texture_p0(struct vc4_job *job,
32                 struct vc4_cl_out **uniforms,
33                 struct vc4_texture_stateobj *texstate,
34                 uint32_t unit)
35{
36        struct vc4_sampler_view *sview =
37                vc4_sampler_view(texstate->textures[unit]);
38        struct vc4_resource *rsc = vc4_resource(sview->base.texture);
39
40        cl_reloc(job, &job->uniforms, uniforms, rsc->bo, sview->texture_p0);
41}
42
43static void
44write_texture_p1(struct vc4_job *job,
45                 struct vc4_cl_out **uniforms,
46                 struct vc4_texture_stateobj *texstate,
47                 uint32_t unit)
48{
49        struct vc4_sampler_view *sview =
50                vc4_sampler_view(texstate->textures[unit]);
51        struct vc4_sampler_state *sampler =
52                vc4_sampler_state(texstate->samplers[unit]);
53
54        cl_aligned_u32(uniforms, sview->texture_p1 | sampler->texture_p1);
55}
56
57static void
58write_texture_p2(struct vc4_job *job,
59                 struct vc4_cl_out **uniforms,
60                 struct vc4_texture_stateobj *texstate,
61                 uint32_t data)
62{
63        uint32_t unit = data & 0xffff;
64        struct pipe_sampler_view *texture = texstate->textures[unit];
65        struct vc4_resource *rsc = vc4_resource(texture->texture);
66
67        cl_aligned_u32(uniforms,
68               VC4_SET_FIELD(VC4_TEX_P2_PTYPE_CUBE_MAP_STRIDE,
69                             VC4_TEX_P2_PTYPE) |
70               VC4_SET_FIELD(rsc->cube_map_stride >> 12, VC4_TEX_P2_CMST) |
71               VC4_SET_FIELD((data >> 16) & 1, VC4_TEX_P2_BSLOD));
72}
73
74static void
75write_texture_first_level(struct vc4_job *job,
76                          struct vc4_cl_out **uniforms,
77                          struct vc4_texture_stateobj *texstate,
78                          uint32_t data)
79{
80        uint32_t unit = data & 0xffff;
81        struct pipe_sampler_view *texture = texstate->textures[unit];
82
83        cl_aligned_f(uniforms, texture->u.tex.first_level);
84}
85
86static void
87write_texture_msaa_addr(struct vc4_job *job,
88                 struct vc4_cl_out **uniforms,
89                        struct vc4_texture_stateobj *texstate,
90                        uint32_t unit)
91{
92        struct pipe_sampler_view *texture = texstate->textures[unit];
93        struct vc4_resource *rsc = vc4_resource(texture->texture);
94
95        cl_aligned_reloc(job, &job->uniforms, uniforms, rsc->bo, 0);
96}
97
98
99#define SWIZ(x,y,z,w) {          \
100        PIPE_SWIZZLE_##x, \
101        PIPE_SWIZZLE_##y, \
102        PIPE_SWIZZLE_##z, \
103        PIPE_SWIZZLE_##w  \
104}
105
106static void
107write_texture_border_color(struct vc4_job *job,
108                           struct vc4_cl_out **uniforms,
109                           struct vc4_texture_stateobj *texstate,
110                           uint32_t unit)
111{
112        struct pipe_sampler_state *sampler = texstate->samplers[unit];
113        struct pipe_sampler_view *texture = texstate->textures[unit];
114        struct vc4_resource *rsc = vc4_resource(texture->texture);
115        union util_color uc;
116
117        const struct util_format_description *tex_format_desc =
118                util_format_description(texture->format);
119
120        float border_color[4];
121        for (int i = 0; i < 4; i++)
122                border_color[i] = sampler->border_color.f[i];
123        if (util_format_is_srgb(texture->format)) {
124                for (int i = 0; i < 3; i++)
125                        border_color[i] =
126                                util_format_linear_to_srgb_float(border_color[i]);
127        }
128
129        /* Turn the border color into the layout of channels that it would
130         * have when stored as texture contents.
131         */
132        float storage_color[4];
133        util_format_unswizzle_4f(storage_color,
134                                 border_color,
135                                 tex_format_desc->swizzle);
136
137        /* Now, pack so that when the vc4_format-sampled texture contents are
138         * replaced with our border color, the vc4_get_format_swizzle()
139         * swizzling will get the right channels.
140         */
141        if (util_format_is_depth_or_stencil(texture->format)) {
142                uc.ui[0] = util_pack_z(PIPE_FORMAT_Z24X8_UNORM,
143                                       sampler->border_color.f[0]) << 8;
144        } else {
145                switch (rsc->vc4_format) {
146                default:
147                case VC4_TEXTURE_TYPE_RGBA8888:
148                        util_pack_color(storage_color,
149                                        PIPE_FORMAT_R8G8B8A8_UNORM, &uc);
150                        break;
151                case VC4_TEXTURE_TYPE_RGBA4444:
152                        util_pack_color(storage_color,
153                                        PIPE_FORMAT_A8B8G8R8_UNORM, &uc);
154                        break;
155                case VC4_TEXTURE_TYPE_RGB565:
156                        util_pack_color(storage_color,
157                                        PIPE_FORMAT_B8G8R8A8_UNORM, &uc);
158                        break;
159                case VC4_TEXTURE_TYPE_ALPHA:
160                        uc.ui[0] = float_to_ubyte(storage_color[0]) << 24;
161                        break;
162                case VC4_TEXTURE_TYPE_LUMALPHA:
163                        uc.ui[0] = ((float_to_ubyte(storage_color[1]) << 24) |
164                                    (float_to_ubyte(storage_color[0]) << 0));
165                        break;
166                }
167        }
168
169        cl_aligned_u32(uniforms, uc.ui[0]);
170}
171
172static uint32_t
173get_texrect_scale(struct vc4_texture_stateobj *texstate,
174                  enum quniform_contents contents,
175                  uint32_t data)
176{
177        struct pipe_sampler_view *texture = texstate->textures[data];
178        uint32_t dim;
179
180        if (contents == QUNIFORM_TEXRECT_SCALE_X)
181                dim = texture->texture->width0;
182        else
183                dim = texture->texture->height0;
184
185        return fui(1.0f / dim);
186}
187
188static struct vc4_bo *
189vc4_upload_ubo(struct vc4_context *vc4,
190               struct vc4_compiled_shader *shader,
191               const uint32_t *gallium_uniforms)
192{
193        if (!shader->ubo_size)
194                return NULL;
195
196        struct vc4_bo *ubo = vc4_bo_alloc(vc4->screen, shader->ubo_size, "ubo");
197        void *data = vc4_bo_map(ubo);
198        for (uint32_t i = 0; i < shader->num_ubo_ranges; i++) {
199                memcpy(data + shader->ubo_ranges[i].dst_offset,
200                       ((const void *)gallium_uniforms +
201                        shader->ubo_ranges[i].src_offset),
202                       shader->ubo_ranges[i].size);
203        }
204
205        return ubo;
206}
207
208void
209vc4_write_uniforms(struct vc4_context *vc4, struct vc4_compiled_shader *shader,
210                   struct vc4_constbuf_stateobj *cb,
211                   struct vc4_texture_stateobj *texstate)
212{
213        struct vc4_shader_uniform_info *uinfo = &shader->uniforms;
214        struct vc4_job *job = vc4->job;
215        const uint32_t *gallium_uniforms = cb->cb[0].user_buffer;
216        struct vc4_bo *ubo = vc4_upload_ubo(vc4, shader, gallium_uniforms);
217
218        cl_ensure_space(&job->uniforms, (uinfo->count +
219                                         uinfo->num_texture_samples) * 4);
220
221        struct vc4_cl_out *uniforms =
222                cl_start_shader_reloc(&job->uniforms,
223                                      uinfo->num_texture_samples);
224
225        for (int i = 0; i < uinfo->count; i++) {
226
227                switch (uinfo->contents[i]) {
228                case QUNIFORM_CONSTANT:
229                        cl_aligned_u32(&uniforms, uinfo->data[i]);
230                        break;
231                case QUNIFORM_UNIFORM:
232                        cl_aligned_u32(&uniforms,
233                                       gallium_uniforms[uinfo->data[i]]);
234                        break;
235                case QUNIFORM_VIEWPORT_X_SCALE:
236                        cl_aligned_f(&uniforms, vc4->viewport.scale[0] * 16.0f);
237                        break;
238                case QUNIFORM_VIEWPORT_Y_SCALE:
239                        cl_aligned_f(&uniforms, vc4->viewport.scale[1] * 16.0f);
240                        break;
241
242                case QUNIFORM_VIEWPORT_Z_OFFSET:
243                        cl_aligned_f(&uniforms, vc4->viewport.translate[2]);
244                        break;
245                case QUNIFORM_VIEWPORT_Z_SCALE:
246                        cl_aligned_f(&uniforms, vc4->viewport.scale[2]);
247                        break;
248
249                case QUNIFORM_USER_CLIP_PLANE:
250                        cl_aligned_f(&uniforms,
251                                     vc4->clip.ucp[uinfo->data[i] / 4][uinfo->data[i] % 4]);
252                        break;
253
254                case QUNIFORM_TEXTURE_CONFIG_P0:
255                        write_texture_p0(job, &uniforms, texstate,
256                                         uinfo->data[i]);
257                        break;
258
259                case QUNIFORM_TEXTURE_CONFIG_P1:
260                        write_texture_p1(job, &uniforms, texstate,
261                                         uinfo->data[i]);
262                        break;
263
264                case QUNIFORM_TEXTURE_CONFIG_P2:
265                        write_texture_p2(job, &uniforms, texstate,
266                                         uinfo->data[i]);
267                        break;
268
269                case QUNIFORM_TEXTURE_FIRST_LEVEL:
270                        write_texture_first_level(job, &uniforms, texstate,
271                                                  uinfo->data[i]);
272                        break;
273
274                case QUNIFORM_UBO_ADDR:
275                        cl_aligned_reloc(job, &job->uniforms, &uniforms, ubo, 0);
276                        break;
277
278                case QUNIFORM_TEXTURE_MSAA_ADDR:
279                        write_texture_msaa_addr(job, &uniforms,
280                                                texstate, uinfo->data[i]);
281                        break;
282
283                case QUNIFORM_TEXTURE_BORDER_COLOR:
284                        write_texture_border_color(job, &uniforms,
285                                                   texstate, uinfo->data[i]);
286                        break;
287
288                case QUNIFORM_TEXRECT_SCALE_X:
289                case QUNIFORM_TEXRECT_SCALE_Y:
290                        cl_aligned_u32(&uniforms,
291                                       get_texrect_scale(texstate,
292                                                         uinfo->contents[i],
293                                                         uinfo->data[i]));
294                        break;
295
296                case QUNIFORM_BLEND_CONST_COLOR_X:
297                case QUNIFORM_BLEND_CONST_COLOR_Y:
298                case QUNIFORM_BLEND_CONST_COLOR_Z:
299                case QUNIFORM_BLEND_CONST_COLOR_W:
300                        cl_aligned_f(&uniforms,
301                                     CLAMP(vc4->blend_color.f.color[uinfo->contents[i] -
302                                                                    QUNIFORM_BLEND_CONST_COLOR_X],
303                                           0, 1));
304                        break;
305
306                case QUNIFORM_BLEND_CONST_COLOR_RGBA: {
307                        const uint8_t *format_swiz =
308                                vc4_get_format_swizzle(vc4->framebuffer.cbufs[0]->format);
309                        uint32_t color = 0;
310                        for (int i = 0; i < 4; i++) {
311                                if (format_swiz[i] >= 4)
312                                        continue;
313
314                                color |= (vc4->blend_color.ub[format_swiz[i]] <<
315                                          (i * 8));
316                        }
317                        cl_aligned_u32(&uniforms, color);
318                        break;
319                }
320
321                case QUNIFORM_BLEND_CONST_COLOR_AAAA: {
322                        uint8_t a = vc4->blend_color.ub[3];
323                        cl_aligned_u32(&uniforms, ((a) |
324                                                   (a << 8) |
325                                                   (a << 16) |
326                                                   (a << 24)));
327                        break;
328                }
329
330                case QUNIFORM_STENCIL:
331                        cl_aligned_u32(&uniforms,
332                                       vc4->zsa->stencil_uniforms[uinfo->data[i]] |
333                                       (uinfo->data[i] <= 1 ?
334                                        (vc4->stencil_ref.ref_value[uinfo->data[i]] << 8) :
335                                        0));
336                        break;
337
338                case QUNIFORM_ALPHA_REF:
339                        cl_aligned_f(&uniforms,
340                                     vc4->zsa->base.alpha.ref_value);
341                        break;
342
343                case QUNIFORM_SAMPLE_MASK:
344                        cl_aligned_u32(&uniforms, vc4->sample_mask);
345                        break;
346
347                case QUNIFORM_UNIFORMS_ADDRESS:
348                        /* This will be filled in by the kernel. */
349                        cl_aligned_u32(&uniforms, 0xd0d0d0d0);
350                        break;
351                }
352#if 0
353                uint32_t written_val = *((uint32_t *)uniforms - 1);
354                fprintf(stderr, "%p: %d / 0x%08x (%f)\n",
355                        shader, i, written_val, uif(written_val));
356#endif
357        }
358
359        cl_end(&job->uniforms, uniforms);
360
361        vc4_bo_unreference(&ubo);
362}
363
364void
365vc4_set_shader_uniform_dirty_flags(struct vc4_compiled_shader *shader)
366{
367        uint32_t dirty = 0;
368
369        for (int i = 0; i < shader->uniforms.count; i++) {
370                switch (shader->uniforms.contents[i]) {
371                case QUNIFORM_CONSTANT:
372                case QUNIFORM_UNIFORMS_ADDRESS:
373                        break;
374                case QUNIFORM_UNIFORM:
375                case QUNIFORM_UBO_ADDR:
376                        dirty |= VC4_DIRTY_CONSTBUF;
377                        break;
378
379                case QUNIFORM_VIEWPORT_X_SCALE:
380                case QUNIFORM_VIEWPORT_Y_SCALE:
381                case QUNIFORM_VIEWPORT_Z_OFFSET:
382                case QUNIFORM_VIEWPORT_Z_SCALE:
383                        dirty |= VC4_DIRTY_VIEWPORT;
384                        break;
385
386                case QUNIFORM_USER_CLIP_PLANE:
387                        dirty |= VC4_DIRTY_CLIP;
388                        break;
389
390                case QUNIFORM_TEXTURE_CONFIG_P0:
391                case QUNIFORM_TEXTURE_CONFIG_P1:
392                case QUNIFORM_TEXTURE_CONFIG_P2:
393                case QUNIFORM_TEXTURE_BORDER_COLOR:
394                case QUNIFORM_TEXTURE_FIRST_LEVEL:
395                case QUNIFORM_TEXTURE_MSAA_ADDR:
396                case QUNIFORM_TEXRECT_SCALE_X:
397                case QUNIFORM_TEXRECT_SCALE_Y:
398                        /* We could flag this on just the stage we're
399                         * compiling for, but it's not passed in.
400                         */
401                        dirty |= VC4_DIRTY_FRAGTEX | VC4_DIRTY_VERTTEX;
402                        break;
403
404                case QUNIFORM_BLEND_CONST_COLOR_X:
405                case QUNIFORM_BLEND_CONST_COLOR_Y:
406                case QUNIFORM_BLEND_CONST_COLOR_Z:
407                case QUNIFORM_BLEND_CONST_COLOR_W:
408                case QUNIFORM_BLEND_CONST_COLOR_RGBA:
409                case QUNIFORM_BLEND_CONST_COLOR_AAAA:
410                        dirty |= VC4_DIRTY_BLEND_COLOR;
411                        break;
412
413                case QUNIFORM_STENCIL:
414                case QUNIFORM_ALPHA_REF:
415                        dirty |= VC4_DIRTY_ZSA;
416                        break;
417
418                case QUNIFORM_SAMPLE_MASK:
419                        dirty |= VC4_DIRTY_SAMPLE_MASK;
420                        break;
421                }
422        }
423
424        shader->uniform_dirty_bits = dirty;
425}
426