1 /**************************************************************************
2 *
3 * Copyright (C) 2014 Red Hat Inc.
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 shall be included
13 * in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR 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
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 * OTHER DEALINGS IN THE SOFTWARE.
22 *
23 **************************************************************************/
24
25 /* gallium blitter implementation in GL */
26 /* for when we can't use glBlitFramebuffer */
27
28 #include <stdio.h>
29
30 #include "util/u_memory.h"
31 #include "util/u_format.h"
32 #include "util/u_texture.h"
33
34 #include "vrend_shader.h"
35 #include "vrend_renderer.h"
36 #include "vrend_blitter.h"
37
38 #define DEST_SWIZZLE_SNIPPET_SIZE 64
39
40 #define BLIT_USE_GLES (1 << 0)
41 #define BLIT_USE_MSAA (1 << 1)
42 #define BLIT_USE_DEPTH (1 << 2)
43
44 struct vrend_blitter_ctx {
45 virgl_gl_context gl_context;
46 bool initialised;
47 bool use_gles;
48
49 GLuint vaoid;
50
51 GLuint vs;
52 GLuint fs_texfetch_col[PIPE_MAX_TEXTURE_TYPES];
53 GLuint fs_texfetch_depth[PIPE_MAX_TEXTURE_TYPES];
54 GLuint fs_texfetch_depth_msaa[PIPE_MAX_TEXTURE_TYPES];
55 GLuint fs_texfetch_col_swizzle;
56 GLuint fb_id;
57
58 // Parameters related to the creation of fs_texfetch_col_swizzle
59 unsigned fs_texfetch_col_swizzle_nr_samples;
60 bool fs_texfetch_col_swizzle_has_swizzle;
61 uint8_t fs_texfetch_col_swizzle_swizzle[4];
62
63 unsigned dst_width;
64 unsigned dst_height;
65
66 GLuint vbo_id;
67 GLfloat vertices[4][2][4]; /**< {pos, color} or {pos, texcoord} */
68 };
69
70 static struct vrend_blitter_ctx vrend_blit_ctx;
71
72 struct vrend_blitter_point {
73 int x;
74 int y;
75 };
76
77 struct vrend_blitter_delta {
78 int dx;
79 int dy;
80 };
81
82 struct swizzle_and_type {
83 char *twm;
84 char *ivec;
85 bool is_array;
86 };
87
build_and_check(GLenum shader_type,const char * buf)88 static GLint build_and_check(GLenum shader_type, const char *buf)
89 {
90 GLint param;
91 GLint id = glCreateShader(shader_type);
92 glShaderSource(id, 1, (const char **)&buf, NULL);
93 glCompileShader(id);
94
95 glGetShaderiv(id, GL_COMPILE_STATUS, ¶m);
96 if (param == GL_FALSE) {
97 char infolog[65536];
98 int len;
99 glGetShaderInfoLog(id, 65536, &len, infolog);
100 vrend_printf("shader failed to compile\n%s\n", infolog);
101 vrend_printf("GLSL:\n%s\n", buf);
102 glDeleteShader(id);
103 return 0;
104 }
105 return id;
106 }
107
link_and_check(GLuint prog_id)108 static bool link_and_check(GLuint prog_id)
109 {
110 GLint lret;
111
112 glLinkProgram(prog_id);
113 glGetProgramiv(prog_id, GL_LINK_STATUS, &lret);
114 if (lret == GL_FALSE) {
115 char infolog[65536];
116 int len;
117 glGetProgramInfoLog(prog_id, 65536, &len, infolog);
118 vrend_printf("got error linking\n%s\n", infolog);
119 /* dump shaders */
120 glDeleteProgram(prog_id);
121 return false;
122 }
123 return true;
124 }
125
create_dest_swizzle_snippet(const uint8_t swizzle[4],char snippet[DEST_SWIZZLE_SNIPPET_SIZE])126 static void create_dest_swizzle_snippet(const uint8_t swizzle[4],
127 char snippet[DEST_SWIZZLE_SNIPPET_SIZE])
128 {
129 static const uint8_t invalid_swizzle = 0xff;
130 ssize_t si = 0;
131 uint8_t inverse[4] = {invalid_swizzle, invalid_swizzle, invalid_swizzle,
132 invalid_swizzle};
133
134 for (int i = 0; i < 4; ++i) {
135 if (swizzle[i] > 3) continue;
136 if (inverse[swizzle[i]] == invalid_swizzle)
137 inverse[swizzle[i]] = i;
138 }
139
140 for (int i = 0; i < 4; ++i) {
141 int res = -1;
142 if (inverse[i] > 3) {
143 /* Use 0.0f for unused color values, 1.0f for an unused alpha value */
144 res = snprintf(&snippet[si], DEST_SWIZZLE_SNIPPET_SIZE - si,
145 i < 3 ? "0.0f, " : "1.0f");
146 } else {
147 res = snprintf(&snippet[si], DEST_SWIZZLE_SNIPPET_SIZE - si,
148 "texel.%c%s", "rgba"[inverse[i]], i < 3 ? ", " : "");
149 }
150 si += res > 0 ? res : 0;
151 }
152 }
153
vec4_type_for_tgsi_ret(enum tgsi_return_type tgsi_ret)154 static const char *vec4_type_for_tgsi_ret(enum tgsi_return_type tgsi_ret)
155 {
156 switch (tgsi_ret) {
157 case TGSI_RETURN_TYPE_SINT: return "ivec4";
158 case TGSI_RETURN_TYPE_UINT: return "uvec4";
159 default: return "vec4";
160 }
161 }
162
tgsi_ret_for_format(enum virgl_formats format)163 static enum tgsi_return_type tgsi_ret_for_format(enum virgl_formats format)
164 {
165 if (util_format_is_pure_uint(format))
166 return TGSI_RETURN_TYPE_UINT;
167 else if (util_format_is_pure_sint(format))
168 return TGSI_RETURN_TYPE_SINT;
169
170 return TGSI_RETURN_TYPE_UNORM;
171 }
172
get_swizzle(int tgsi_tex_target,unsigned flags,struct swizzle_and_type * retval)173 static void get_swizzle(int tgsi_tex_target, unsigned flags,
174 struct swizzle_and_type *retval)
175 {
176 retval->twm = "";
177 retval->ivec = "";
178 retval->is_array = false;
179 switch (tgsi_tex_target) {
180 case TGSI_TEXTURE_1D:
181 if (flags & (BLIT_USE_GLES | BLIT_USE_DEPTH)) {
182 retval->twm = ".xy";
183 break;
184 }
185 /* fallthrough */
186 case TGSI_TEXTURE_BUFFER:
187 retval->twm = ".x";
188 break;
189 case TGSI_TEXTURE_2D_MSAA:
190 if (flags & BLIT_USE_MSAA) {
191 retval->ivec = "ivec2";
192 }
193 /* fallthrough */
194 case TGSI_TEXTURE_1D_ARRAY:
195 case TGSI_TEXTURE_2D:
196 case TGSI_TEXTURE_RECT:
197 retval->twm = ".xy";
198 break;
199 case TGSI_TEXTURE_2D_ARRAY_MSAA:
200 if (flags & BLIT_USE_MSAA) {
201 retval->ivec = "ivec3";
202 retval->is_array = true;
203 }
204 /* fallthrough */
205 case TGSI_TEXTURE_SHADOW1D:
206 case TGSI_TEXTURE_SHADOW2D:
207 case TGSI_TEXTURE_SHADOW1D_ARRAY:
208 case TGSI_TEXTURE_SHADOWRECT:
209 case TGSI_TEXTURE_3D:
210 case TGSI_TEXTURE_CUBE:
211 case TGSI_TEXTURE_2D_ARRAY:
212 retval->twm = ".xyz";
213 break;
214 case TGSI_TEXTURE_SHADOWCUBE:
215 case TGSI_TEXTURE_SHADOW2D_ARRAY:
216 case TGSI_TEXTURE_SHADOWCUBE_ARRAY:
217 case TGSI_TEXTURE_CUBE_ARRAY:
218 retval->twm = "";
219 break;
220 default:
221 if (flags & BLIT_USE_MSAA) {
222 break;
223 }
224 retval->twm = ".xy";
225 break;
226 }
227 }
228
blit_build_frag_tex_col(struct vrend_blitter_ctx * blit_ctx,int tgsi_tex_target,enum tgsi_return_type tgsi_ret,const uint8_t swizzle[4],int nr_samples)229 static GLuint blit_build_frag_tex_col(struct vrend_blitter_ctx *blit_ctx,
230 int tgsi_tex_target,
231 enum tgsi_return_type tgsi_ret,
232 const uint8_t swizzle[4],
233 int nr_samples)
234 {
235 char shader_buf[4096];
236 struct swizzle_and_type retval;
237 unsigned flags = 0;
238 char dest_swizzle_snippet[DEST_SWIZZLE_SNIPPET_SIZE] = "texel";
239 const char *ext_str = "";
240 bool msaa = nr_samples > 0;
241
242 if (msaa && !blit_ctx->use_gles)
243 ext_str = "#extension GL_ARB_texture_multisample : enable\n";
244 else if (tgsi_tex_target == TGSI_TEXTURE_CUBE_ARRAY ||
245 tgsi_tex_target == TGSI_TEXTURE_SHADOWCUBE_ARRAY)
246 ext_str = "#extension GL_ARB_texture_cube_map_array : require\n";
247
248 if (blit_ctx->use_gles)
249 flags |= BLIT_USE_GLES;
250 if (msaa)
251 flags |= BLIT_USE_MSAA;
252 get_swizzle(tgsi_tex_target, flags, &retval);
253
254 if (swizzle)
255 create_dest_swizzle_snippet(swizzle, dest_swizzle_snippet);
256
257 if (msaa)
258 snprintf(shader_buf, 4096, blit_ctx->use_gles ?
259 (retval.is_array ? FS_TEXFETCH_COL_MSAA_ARRAY_GLES
260 : FS_TEXFETCH_COL_MSAA_GLES)
261 : FS_TEXFETCH_COL_MSAA_GL,
262 ext_str, vec4_type_for_tgsi_ret(tgsi_ret),
263 vrend_shader_samplerreturnconv(tgsi_ret),
264 vrend_shader_samplertypeconv(blit_ctx->use_gles, tgsi_tex_target),
265 nr_samples, retval.ivec, retval.twm, dest_swizzle_snippet);
266 else
267 snprintf(shader_buf, 4096, blit_ctx->use_gles ?
268 (tgsi_tex_target == TGSI_TEXTURE_1D ?
269 FS_TEXFETCH_COL_GLES_1D : FS_TEXFETCH_COL_GLES)
270 : FS_TEXFETCH_COL_GL,
271 ext_str, vec4_type_for_tgsi_ret(tgsi_ret),
272 vrend_shader_samplerreturnconv(tgsi_ret),
273 vrend_shader_samplertypeconv(blit_ctx->use_gles, tgsi_tex_target),
274 retval.twm, dest_swizzle_snippet);
275
276 VREND_DEBUG(dbg_blit, NULL, "-- Blit FS shader MSAA: %d -----------------\n"
277 "%s\n---------------------------------------\n", msaa, shader_buf);
278
279 return build_and_check(GL_FRAGMENT_SHADER, shader_buf);
280 }
281
blit_build_frag_depth(struct vrend_blitter_ctx * blit_ctx,int tgsi_tex_target,bool msaa)282 static GLuint blit_build_frag_depth(struct vrend_blitter_ctx *blit_ctx, int tgsi_tex_target, bool msaa)
283 {
284 char shader_buf[4096];
285 struct swizzle_and_type retval;
286 unsigned flags = BLIT_USE_DEPTH;
287
288 if (msaa)
289 flags |= BLIT_USE_MSAA;
290
291 get_swizzle(tgsi_tex_target, flags, &retval);
292
293 if (msaa)
294 snprintf(shader_buf, 4096, blit_ctx->use_gles ?
295 (retval.is_array ? FS_TEXFETCH_DS_MSAA_ARRAY_GLES : FS_TEXFETCH_DS_MSAA_GLES)
296 : FS_TEXFETCH_DS_MSAA_GL,
297 vrend_shader_samplertypeconv(blit_ctx->use_gles, tgsi_tex_target), retval.ivec, retval.twm);
298 else
299 snprintf(shader_buf, 4096, blit_ctx->use_gles ? FS_TEXFETCH_DS_GLES : FS_TEXFETCH_DS_GL,
300 vrend_shader_samplertypeconv(blit_ctx->use_gles, tgsi_tex_target), retval.twm);
301
302 return build_and_check(GL_FRAGMENT_SHADER, shader_buf);
303 }
304
blit_get_frag_tex_writedepth(struct vrend_blitter_ctx * blit_ctx,int pipe_tex_target,unsigned nr_samples)305 static GLuint blit_get_frag_tex_writedepth(struct vrend_blitter_ctx *blit_ctx, int pipe_tex_target, unsigned nr_samples)
306 {
307 assert(pipe_tex_target < PIPE_MAX_TEXTURE_TYPES);
308
309 GLuint *shader = nr_samples > 0 ? &blit_ctx->fs_texfetch_depth_msaa[pipe_tex_target]
310 : &blit_ctx->fs_texfetch_depth[pipe_tex_target];
311
312 if (!*shader) {
313 unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(pipe_tex_target, nr_samples);
314 *shader = blit_build_frag_depth(blit_ctx, tgsi_tex, nr_samples > 0);
315 }
316 return *shader;
317 }
318
blit_get_frag_tex_col(struct vrend_blitter_ctx * blit_ctx,int pipe_tex_target,unsigned nr_samples,const struct vrend_format_table * src_entry,uint8_t swizzle[static4])319 static GLuint blit_get_frag_tex_col(struct vrend_blitter_ctx *blit_ctx,
320 int pipe_tex_target,
321 unsigned nr_samples,
322 const struct vrend_format_table *src_entry,
323 uint8_t swizzle[static 4])
324 {
325 assert(pipe_tex_target < PIPE_MAX_TEXTURE_TYPES);
326
327 bool needs_swizzle = false;
328 for (uint i = 0; i < 4; ++i) {
329 if (swizzle[i] != i) {
330 needs_swizzle = true;
331 break;
332 }
333 }
334
335 GLuint *shader;
336 if (needs_swizzle || nr_samples > 1) {
337 shader = &blit_ctx->fs_texfetch_col_swizzle;
338 if (*shader &&
339 (blit_ctx->fs_texfetch_col_swizzle_nr_samples != nr_samples ||
340 blit_ctx->fs_texfetch_col_swizzle_has_swizzle != needs_swizzle ||
341 (needs_swizzle && memcmp(blit_ctx->fs_texfetch_col_swizzle_swizzle, swizzle, 4)))) {
342 glDeleteShader(*shader);
343 *shader = 0;
344 }
345 blit_ctx->fs_texfetch_col_swizzle_has_swizzle = needs_swizzle;
346 if (needs_swizzle)
347 memcpy(blit_ctx->fs_texfetch_col_swizzle_swizzle, swizzle, 4);
348 blit_ctx->fs_texfetch_col_swizzle_nr_samples = nr_samples;
349 } else {
350 shader = &blit_ctx->fs_texfetch_col[pipe_tex_target];
351 }
352
353 if (!*shader) {
354
355 unsigned tgsi_tex = util_pipe_tex_to_tgsi_tex(pipe_tex_target, nr_samples);
356 enum tgsi_return_type tgsi_ret = tgsi_ret_for_format(src_entry->format);
357
358 // Integer textures are resolved using just one sample
359 int msaa_samples = nr_samples > 0 ? (tgsi_ret == TGSI_RETURN_TYPE_UNORM ? nr_samples : 1) : 0;
360
361 *shader = blit_build_frag_tex_col(blit_ctx, tgsi_tex, tgsi_ret,
362 swizzle, msaa_samples);
363 }
364 return *shader;
365 }
366
vrend_renderer_init_blit_ctx(struct vrend_blitter_ctx * blit_ctx)367 static void vrend_renderer_init_blit_ctx(struct vrend_blitter_ctx *blit_ctx)
368 {
369 struct virgl_gl_ctx_param ctx_params;
370 int i;
371 if (blit_ctx->initialised) {
372 vrend_sync_make_current(blit_ctx->gl_context);
373 return;
374 }
375
376 blit_ctx->initialised = true;
377 blit_ctx->use_gles = epoxy_is_desktop_gl() == 0;
378 ctx_params.shared = true;
379 for (uint32_t i = 0; i < ARRAY_SIZE(gl_versions); i++) {
380 ctx_params.major_ver = gl_versions[i].major;
381 ctx_params.minor_ver = gl_versions[i].minor;
382
383 blit_ctx->gl_context = vrend_clicbs->create_gl_context(0, &ctx_params);
384 if (blit_ctx->gl_context)
385 break;
386 }
387
388 vrend_sync_make_current(blit_ctx->gl_context);
389 glGenVertexArrays(1, &blit_ctx->vaoid);
390 glGenFramebuffers(1, &blit_ctx->fb_id);
391
392 glGenBuffers(1, &blit_ctx->vbo_id);
393 blit_ctx->vs = build_and_check(GL_VERTEX_SHADER,
394 blit_ctx->use_gles ? VS_PASSTHROUGH_GLES : VS_PASSTHROUGH_GL);
395
396 for (i = 0; i < 4; i++)
397 blit_ctx->vertices[i][0][3] = 1; /*v.w*/
398 glBindVertexArray(blit_ctx->vaoid);
399 glBindBuffer(GL_ARRAY_BUFFER, blit_ctx->vbo_id);
400
401 if (!blit_ctx->use_gles)
402 glEnable(GL_FRAMEBUFFER_SRGB);
403 }
404
blitter_set_rectangle(struct vrend_blitter_ctx * blit_ctx,int x1,int y1,int x2,int y2,float depth)405 static void blitter_set_rectangle(struct vrend_blitter_ctx *blit_ctx,
406 int x1, int y1, int x2, int y2,
407 float depth)
408 {
409 int i;
410
411 /* set vertex positions */
412 blit_ctx->vertices[0][0][0] = (float)x1 / blit_ctx->dst_width * 2.0f - 1.0f; /*v0.x*/
413 blit_ctx->vertices[0][0][1] = (float)y1 / blit_ctx->dst_height * 2.0f - 1.0f; /*v0.y*/
414
415 blit_ctx->vertices[1][0][0] = (float)x2 / blit_ctx->dst_width * 2.0f - 1.0f; /*v1.x*/
416 blit_ctx->vertices[1][0][1] = (float)y1 / blit_ctx->dst_height * 2.0f - 1.0f; /*v1.y*/
417
418 blit_ctx->vertices[2][0][0] = (float)x2 / blit_ctx->dst_width * 2.0f - 1.0f; /*v2.x*/
419 blit_ctx->vertices[2][0][1] = (float)y2 / blit_ctx->dst_height * 2.0f - 1.0f; /*v2.y*/
420
421 blit_ctx->vertices[3][0][0] = (float)x1 / blit_ctx->dst_width * 2.0f - 1.0f; /*v3.x*/
422 blit_ctx->vertices[3][0][1] = (float)y2 / blit_ctx->dst_height * 2.0f - 1.0f; /*v3.y*/
423
424 for (i = 0; i < 4; i++)
425 blit_ctx->vertices[i][0][2] = depth; /*z*/
426
427 glViewport(0, 0, blit_ctx->dst_width, blit_ctx->dst_height);
428 }
429
get_texcoords(struct vrend_blitter_ctx * blit_ctx,struct vrend_resource * src_res,int src_level,int x1,int y1,int x2,int y2,float out[4])430 static void get_texcoords(struct vrend_blitter_ctx *blit_ctx,
431 struct vrend_resource *src_res,
432 int src_level,
433 int x1, int y1, int x2, int y2,
434 float out[4])
435 {
436 bool normalized = (src_res->base.target != PIPE_TEXTURE_RECT || blit_ctx->use_gles) &&
437 src_res->base.nr_samples < 1;
438
439 if (normalized) {
440 out[0] = x1 / (float)u_minify(src_res->base.width0, src_level);
441 out[1] = y1 / (float)u_minify(src_res->base.height0, src_level);
442 out[2] = x2 / (float)u_minify(src_res->base.width0, src_level);
443 out[3] = y2 / (float)u_minify(src_res->base.height0, src_level);
444 } else {
445 out[0] = (float) x1;
446 out[1] = (float) y1;
447 out[2] = (float) x2;
448 out[3] = (float) y2;
449 }
450 }
451
set_texcoords_in_vertices(const float coord[4],float * out,unsigned stride)452 static void set_texcoords_in_vertices(const float coord[4],
453 float *out, unsigned stride)
454 {
455 out[0] = coord[0]; /*t0.s*/
456 out[1] = coord[1]; /*t0.t*/
457 out += stride;
458 out[0] = coord[2]; /*t1.s*/
459 out[1] = coord[1]; /*t1.t*/
460 out += stride;
461 out[0] = coord[2]; /*t2.s*/
462 out[1] = coord[3]; /*t2.t*/
463 out += stride;
464 out[0] = coord[0]; /*t3.s*/
465 out[1] = coord[3]; /*t3.t*/
466 }
467
blitter_set_texcoords(struct vrend_blitter_ctx * blit_ctx,struct vrend_resource * src_res,int level,float layer,unsigned sample,int x1,int y1,int x2,int y2)468 static void blitter_set_texcoords(struct vrend_blitter_ctx *blit_ctx,
469 struct vrend_resource *src_res,
470 int level,
471 float layer, unsigned sample,
472 int x1, int y1, int x2, int y2)
473 {
474 float coord[4];
475 float face_coord[4][2];
476 int i;
477 get_texcoords(blit_ctx, src_res, level, x1, y1, x2, y2, coord);
478
479 if (src_res->base.target == PIPE_TEXTURE_CUBE ||
480 src_res->base.target == PIPE_TEXTURE_CUBE_ARRAY) {
481 set_texcoords_in_vertices(coord, &face_coord[0][0], 2);
482 util_map_texcoords2d_onto_cubemap((unsigned)layer % 6,
483 /* pointer, stride in floats */
484 &face_coord[0][0], 2,
485 &blit_ctx->vertices[0][1][0], 8,
486 FALSE);
487 } else {
488 set_texcoords_in_vertices(coord, &blit_ctx->vertices[0][1][0], 8);
489 }
490
491 switch (src_res->base.target) {
492 case PIPE_TEXTURE_3D:
493 {
494 float r = layer / (float)u_minify(src_res->base.depth0,
495 level);
496 for (i = 0; i < 4; i++)
497 blit_ctx->vertices[i][1][2] = r; /*r*/
498 }
499 break;
500
501 case PIPE_TEXTURE_1D_ARRAY:
502 for (i = 0; i < 4; i++)
503 blit_ctx->vertices[i][1][1] = (float) layer; /*t*/
504 break;
505
506 case PIPE_TEXTURE_2D_ARRAY:
507 for (i = 0; i < 4; i++) {
508 blit_ctx->vertices[i][1][2] = (float) layer; /*r*/
509 blit_ctx->vertices[i][1][3] = (float) sample; /*q*/
510 }
511 break;
512 case PIPE_TEXTURE_CUBE_ARRAY:
513 for (i = 0; i < 4; i++)
514 blit_ctx->vertices[i][1][3] = (float) ((unsigned)layer / 6); /*w*/
515 break;
516 case PIPE_TEXTURE_2D:
517 for (i = 0; i < 4; i++) {
518 blit_ctx->vertices[i][1][3] = (float) sample; /*r*/
519 }
520 break;
521 default:;
522 }
523 }
524 #if 0
525 static void set_dsa_keep_depth_stencil(void)
526 {
527 glDisable(GL_STENCIL_TEST);
528 glDisable(GL_DEPTH_TEST);
529 glDepthMask(GL_FALSE);
530 }
531 #endif
532
set_dsa_write_depth_keep_stencil(void)533 static void set_dsa_write_depth_keep_stencil(void)
534 {
535 glDisable(GL_STENCIL_TEST);
536 glEnable(GL_DEPTH_TEST);
537 glDepthFunc(GL_ALWAYS);
538 glDepthMask(GL_TRUE);
539 }
540
to_gl_swizzle(int swizzle)541 static inline GLenum to_gl_swizzle(int swizzle)
542 {
543 switch (swizzle) {
544 case PIPE_SWIZZLE_RED: return GL_RED;
545 case PIPE_SWIZZLE_GREEN: return GL_GREEN;
546 case PIPE_SWIZZLE_BLUE: return GL_BLUE;
547 case PIPE_SWIZZLE_ALPHA: return GL_ALPHA;
548 case PIPE_SWIZZLE_ZERO: return GL_ZERO;
549 case PIPE_SWIZZLE_ONE: return GL_ONE;
550 default:
551 assert(0);
552 return 0;
553 }
554 }
555
556 /* Calculate the delta required to keep 'v' within [0, max] */
calc_delta_for_bound(int v,int max)557 static int calc_delta_for_bound(int v, int max)
558 {
559 int delta = 0;
560
561 if (v < 0)
562 delta = -v;
563 else if (v > max)
564 delta = - (v - max);
565
566 return delta;
567 }
568
569 /* Calculate the deltas for the source blit region points in order to bound
570 * them within the source resource extents */
calc_src_deltas_for_bounds(struct vrend_resource * src_res,const struct pipe_blit_info * info,struct vrend_blitter_delta * src0_delta,struct vrend_blitter_delta * src1_delta)571 static void calc_src_deltas_for_bounds(struct vrend_resource *src_res,
572 const struct pipe_blit_info *info,
573 struct vrend_blitter_delta *src0_delta,
574 struct vrend_blitter_delta *src1_delta)
575 {
576 int max_x = u_minify(src_res->base.width0, info->src.level) - 1;
577 int max_y = u_minify(src_res->base.height0, info->src.level) - 1;
578
579 /* Whether the bounds for the coordinates of a point are inclusive or
580 * exclusive depends on the direction of the blit read. Adjust the max
581 * bounds accordingly, with an adjustment of 0 for inclusive, and 1 for
582 * exclusive. */
583 int src0_x_excl = info->src.box.width < 0;
584 int src0_y_excl = info->src.box.height < 0;
585
586 src0_delta->dx = calc_delta_for_bound(info->src.box.x, max_x + src0_x_excl);
587 src0_delta->dy = calc_delta_for_bound(info->src.box.y, max_y + src0_y_excl);
588
589 src1_delta->dx = calc_delta_for_bound(info->src.box.x + info->src.box.width,
590 max_x + !src0_x_excl);
591 src1_delta->dy = calc_delta_for_bound(info->src.box.y + info->src.box.height,
592 max_y + !src0_y_excl);
593 }
594
595 /* Calculate dst delta values to adjust the dst points for any changes in the
596 * src points */
calc_dst_deltas_from_src(const struct pipe_blit_info * info,const struct vrend_blitter_delta * src0_delta,const struct vrend_blitter_delta * src1_delta,struct vrend_blitter_delta * dst0_delta,struct vrend_blitter_delta * dst1_delta)597 static void calc_dst_deltas_from_src(const struct pipe_blit_info *info,
598 const struct vrend_blitter_delta *src0_delta,
599 const struct vrend_blitter_delta *src1_delta,
600 struct vrend_blitter_delta *dst0_delta,
601 struct vrend_blitter_delta *dst1_delta)
602 {
603 float scale_x = (float)info->dst.box.width / (float)info->src.box.width;
604 float scale_y = (float)info->dst.box.height / (float)info->src.box.height;
605
606 dst0_delta->dx = src0_delta->dx * scale_x;
607 dst0_delta->dy = src0_delta->dy * scale_y;
608
609 dst1_delta->dx = src1_delta->dx * scale_x;
610 dst1_delta->dy = src1_delta->dy * scale_y;
611 }
612
blitter_set_points(struct vrend_blitter_ctx * blit_ctx,const struct pipe_blit_info * info,struct vrend_resource * src_res,struct vrend_resource * dst_res,struct vrend_blitter_point * src0,struct vrend_blitter_point * src1)613 static void blitter_set_points(struct vrend_blitter_ctx *blit_ctx,
614 const struct pipe_blit_info *info,
615 struct vrend_resource *src_res,
616 struct vrend_resource *dst_res,
617 struct vrend_blitter_point *src0,
618 struct vrend_blitter_point *src1)
619 {
620 struct vrend_blitter_point dst0, dst1;
621 struct vrend_blitter_delta src0_delta, src1_delta, dst0_delta, dst1_delta;
622
623 blit_ctx->dst_width = u_minify(dst_res->base.width0, info->dst.level);
624 blit_ctx->dst_height = u_minify(dst_res->base.height0, info->dst.level);
625
626 /* Calculate src and dst points taking deltas into account */
627 calc_src_deltas_for_bounds(src_res, info, &src0_delta, &src1_delta);
628 calc_dst_deltas_from_src(info, &src0_delta, &src1_delta, &dst0_delta, &dst1_delta);
629
630 src0->x = info->src.box.x + src0_delta.dx;
631 src0->y = info->src.box.y + src0_delta.dy;
632 src1->x = info->src.box.x + info->src.box.width + src1_delta.dx;
633 src1->y = info->src.box.y + info->src.box.height + src1_delta.dy;
634
635 dst0.x = info->dst.box.x + dst0_delta.dx;
636 dst0.y = info->dst.box.y + dst0_delta.dy;
637 dst1.x = info->dst.box.x + info->dst.box.width + dst1_delta.dx;
638 dst1.y = info->dst.box.y + info->dst.box.height + dst1_delta.dy;
639
640 VREND_DEBUG(dbg_blit, NULL, "Blitter src:[%3d, %3d] - [%3d, %3d] to dst:[%3d, %3d] - [%3d, %3d]\n",
641 src0->x, src0->y, src1->x, src1->y,
642 dst0.x, dst0.y, dst1.x, dst1.y);
643
644 blitter_set_rectangle(blit_ctx, dst0.x, dst0.y, dst1.x, dst1.y, 0);
645 }
646
vrend_set_tex_param(struct vrend_resource * src_res,const struct pipe_blit_info * info,bool has_texture_srgb_decode)647 static void vrend_set_tex_param(struct vrend_resource *src_res,
648 const struct pipe_blit_info *info,
649 bool has_texture_srgb_decode)
650 {
651 const struct vrend_format_table *src_entry =
652 vrend_get_format_table_entry(info->src.format);
653
654 if (src_entry->flags & VIRGL_TEXTURE_NEED_SWIZZLE) {
655 glTexParameteri(src_res->target, GL_TEXTURE_SWIZZLE_R,
656 to_gl_swizzle(src_entry->swizzle[0]));
657 glTexParameteri(src_res->target, GL_TEXTURE_SWIZZLE_G,
658 to_gl_swizzle(src_entry->swizzle[1]));
659 glTexParameteri(src_res->target, GL_TEXTURE_SWIZZLE_B,
660 to_gl_swizzle(src_entry->swizzle[2]));
661 glTexParameteri(src_res->target, GL_TEXTURE_SWIZZLE_A,
662 to_gl_swizzle(src_entry->swizzle[3]));
663 }
664
665 /* Just make sure that no stale state disabled decoding */
666 if (has_texture_srgb_decode && util_format_is_srgb(info->src.format) &&
667 src_res->base.nr_samples < 1)
668 glTexParameteri(src_res->target, GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT);
669
670 if (src_res->base.nr_samples < 1) {
671 glTexParameteri(src_res->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
672 glTexParameteri(src_res->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
673 glTexParameteri(src_res->target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
674 }
675
676 glTexParameteri(src_res->target, GL_TEXTURE_BASE_LEVEL, info->src.level);
677 glTexParameteri(src_res->target, GL_TEXTURE_MAX_LEVEL, info->src.level);
678
679 if (src_res->base.nr_samples < 1) {
680 GLenum filter = info->filter == PIPE_TEX_FILTER_NEAREST ?
681 GL_NEAREST : GL_LINEAR;
682 glTexParameteri(src_res->target, GL_TEXTURE_MAG_FILTER, filter);
683 glTexParameteri(src_res->target, GL_TEXTURE_MIN_FILTER, filter);
684 }
685 }
686
vrend_set_vertex_param(GLuint prog_id)687 static void vrend_set_vertex_param(GLuint prog_id)
688 {
689 GLuint pos_loc, tc_loc;
690
691 pos_loc = glGetAttribLocation(prog_id, "arg0");
692 tc_loc = glGetAttribLocation(prog_id, "arg1");
693
694 glVertexAttribPointer(pos_loc, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)0);
695 glVertexAttribPointer(tc_loc, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void *)(4 * sizeof(float)));
696
697 glEnableVertexAttribArray(pos_loc);
698 glEnableVertexAttribArray(tc_loc);
699 }
700
701 /* implement blitting using OpenGL. */
vrend_renderer_blit_gl(MAYBE_UNUSED struct vrend_context * ctx,struct vrend_resource * src_res,struct vrend_resource * dst_res,GLenum blit_views[2],const struct pipe_blit_info * info,bool has_texture_srgb_decode,bool has_srgb_write_control,uint8_t swizzle[static4])702 void vrend_renderer_blit_gl(MAYBE_UNUSED struct vrend_context *ctx,
703 struct vrend_resource *src_res,
704 struct vrend_resource *dst_res,
705 GLenum blit_views[2],
706 const struct pipe_blit_info *info,
707 bool has_texture_srgb_decode,
708 bool has_srgb_write_control,
709 uint8_t swizzle[static 4])
710 {
711 struct vrend_blitter_ctx *blit_ctx = &vrend_blit_ctx;
712 GLuint buffers;
713 GLuint prog_id;
714 GLuint fs_id;
715 bool has_depth, has_stencil;
716 bool blit_stencil, blit_depth;
717 int dst_z;
718 struct vrend_blitter_point src0, src1;
719 const struct util_format_description *src_desc =
720 util_format_description(src_res->base.format);
721 const struct util_format_description *dst_desc =
722 util_format_description(dst_res->base.format);
723 const struct vrend_format_table *orig_src_entry = vrend_get_format_table_entry(info->src.format);
724
725 has_depth = util_format_has_depth(src_desc) &&
726 util_format_has_depth(dst_desc);
727 has_stencil = util_format_has_stencil(src_desc) &&
728 util_format_has_stencil(dst_desc);
729
730 blit_depth = has_depth && (info->mask & PIPE_MASK_Z);
731 blit_stencil = has_stencil && (info->mask & PIPE_MASK_S) & 0;
732
733 vrend_renderer_init_blit_ctx(blit_ctx);
734 blitter_set_points(blit_ctx, info, src_res, dst_res, &src0, &src1);
735
736 prog_id = glCreateProgram();
737 glAttachShader(prog_id, blit_ctx->vs);
738
739 if (blit_depth || blit_stencil) {
740 fs_id = blit_get_frag_tex_writedepth(blit_ctx, src_res->base.target,
741 src_res->base.nr_samples);
742 } else {
743 VREND_DEBUG(dbg_blit, ctx, "BLIT: applying swizzle during blit: (%d %d %d %d)\n",
744 swizzle[0], swizzle[1], swizzle[2], swizzle[3]);
745 fs_id = blit_get_frag_tex_col(blit_ctx, src_res->base.target,
746 src_res->base.nr_samples,
747 orig_src_entry,
748 swizzle);
749 }
750 glAttachShader(prog_id, fs_id);
751
752 if(!link_and_check(prog_id))
753 return;
754
755 glUseProgram(prog_id);
756
757 glBindFramebuffer(GL_FRAMEBUFFER, blit_ctx->fb_id);
758 vrend_fb_bind_texture_id(dst_res, blit_views[1], 0, info->dst.level, info->dst.box.z, 0);
759
760 buffers = GL_COLOR_ATTACHMENT0;
761 glDrawBuffers(1, &buffers);
762
763 glBindTexture(src_res->target, blit_views[0]);
764 vrend_set_tex_param(src_res, info, has_texture_srgb_decode);
765 vrend_set_vertex_param(prog_id);
766
767 set_dsa_write_depth_keep_stencil();
768
769 if (info->scissor_enable) {
770 glScissor(info->scissor.minx, info->scissor.miny, info->scissor.maxx - info->scissor.minx, info->scissor.maxy - info->scissor.miny);
771 glEnable(GL_SCISSOR_TEST);
772 } else
773 glDisable(GL_SCISSOR_TEST);
774
775 if (has_srgb_write_control) {
776 if (util_format_is_srgb(info->dst.format) || util_format_is_srgb(info->src.format)) {
777 VREND_DEBUG(dbg_blit, ctx, "%s: Enable GL_FRAMEBUFFER_SRGB\n", __func__);
778 glEnable(GL_FRAMEBUFFER_SRGB);
779 } else {
780 VREND_DEBUG(dbg_blit, ctx, "%s: Disable GL_FRAMEBUFFER_SRGB\n", __func__);
781 glDisable(GL_FRAMEBUFFER_SRGB);
782 }
783 }
784
785 for (dst_z = 0; dst_z < info->dst.box.depth; dst_z++) {
786 float dst2src_scale = info->src.box.depth / (float)info->dst.box.depth;
787 float dst_offset = ((info->src.box.depth - 1) -
788 (info->dst.box.depth - 1) * dst2src_scale) * 0.5;
789 float src_z = (dst_z + dst_offset) * dst2src_scale;
790 uint32_t layer = (dst_res->target == GL_TEXTURE_CUBE_MAP ||
791 dst_res->target == GL_TEXTURE_1D_ARRAY ||
792 dst_res->target == GL_TEXTURE_2D_ARRAY) ? info->dst.box.z : dst_z;
793
794 glBindFramebuffer(GL_FRAMEBUFFER, blit_ctx->fb_id);
795 vrend_fb_bind_texture_id(dst_res, blit_views[1], 0, info->dst.level, layer, 0);
796
797 buffers = GL_COLOR_ATTACHMENT0;
798 glDrawBuffers(1, &buffers);
799 blitter_set_texcoords(blit_ctx, src_res, info->src.level,
800 info->src.box.z + src_z, 0,
801 src0.x, src0.y, src1.x, src1.y);
802
803 glBufferData(GL_ARRAY_BUFFER, sizeof(blit_ctx->vertices), blit_ctx->vertices, GL_STATIC_DRAW);
804 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
805 }
806
807 glUseProgram(0);
808 glDeleteProgram(prog_id);
809 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
810 GL_TEXTURE_2D, 0, 0);
811 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
812 GL_TEXTURE_2D, 0, 0);
813 glBindTexture(src_res->target, 0);
814 }
815
vrend_blitter_fini(void)816 void vrend_blitter_fini(void)
817 {
818 vrend_blit_ctx.initialised = false;
819 vrend_clicbs->destroy_gl_context(vrend_blit_ctx.gl_context);
820 memset(&vrend_blit_ctx, 0, sizeof(vrend_blit_ctx));
821 }
822