VirtualBox

source: vbox/trunk/src/VBox/Devices/Graphics/DevVGA-SVGA3d-glHlp.cpp

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.6 KB
Line 
1/* $Id: DevVGA-SVGA3d-glHlp.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * DevVMWare - VMWare SVGA device OpenGL backend
4 */
5
6/*
7 * Copyright (C) 2013-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#ifdef DEBUG_bird
33//# define RTMEM_WRAP_TO_EF_APIS
34#endif
35#define LOG_GROUP LOG_GROUP_DEV_VMSVGA
36#include <VBox/vmm/pdmdev.h>
37
38#include <iprt/assert.h>
39#include <iprt/mem.h>
40
41#include "DevVGA-SVGA.h"
42#include "DevVGA-SVGA3d-internal.h"
43
44/* Parameters for glVertexAttribPointer. */
45typedef struct VertexAttribDesc
46{
47 GLint size;
48 GLenum type;
49 GLboolean normalized;
50 GLsizei stride;
51 GLsizei offset;
52} VertexAttribDesc;
53
54/* Information about a shader program. */
55typedef struct ShaderProgram
56{
57 GLuint vertexShader; /* Vertex shader name. */
58 GLuint fragmentShader; /* Fragment shader name. */
59 GLuint program; /* Shader program name. */
60 GLint sSourceTex; /* Location of the texture sampler uniform in the shader. */
61 GLint uTexInfo; /* Location of the texture information uniform in the shader. */
62} ShaderProgram;
63
64/* Texture format conversion data.
65 * Uses a fragment (pixel) shader to render a source texture in one format
66 * to the target texture in another format.
67 */
68typedef struct VMSVGA3DFORMATCONVERTER
69{
70 PVMSVGA3DSTATE pState;
71
72 ShaderProgram programYUY2ToRGB; /* From the YUY2 emulated format to the actual RGB texture. */
73 ShaderProgram programYUY2FromRGB; /* From the actual RGB texture to the emulated YUY2 format. */
74 ShaderProgram programUYVYToRGB; /* From the UYVY emulated format to the actual RGB texture. */
75 ShaderProgram programUYVYFromRGB; /* From the actual RGB texture to the emulated UYVY format. */
76
77 GLuint framebuffer; /* Framebuffer object name. */
78
79 GLuint vertexBuffer; /* Vertex attribute buffer. Position + texcoord. */
80} VMSVGA3DFORMATCONVERTER;
81
82/* Parameters for glVertexAttribPointer. */
83static const VertexAttribDesc aVertexAttribs[] =
84{
85 {2, GL_FLOAT, GL_FALSE, 16, 0 }, /* Position. */
86 {2, GL_FLOAT, GL_FALSE, 16, 8 } /* Texcoord. */
87};
88
89/* Triangle fan */
90static float const aAttribData[] =
91{
92 /* positions texcoords */
93 -1.0f, -1.0f, 0.0f, 0.0f,
94 1.0f, -1.0f, 1.0f, 0.0f,
95 1.0f, 1.0f, 1.0f, 1.0f,
96 -1.0f, 1.0f, 0.0f, 1.0f
97};
98
99static const GLchar shaderHeaderSource[] =
100{
101 " #version 120\n"
102};
103
104static const GLchar vertexShaderSource[] =
105{
106 " attribute vec2 attrib0;\n"
107 " attribute vec2 attrib1;\n"
108 " void main(void)\n"
109 " {\n"
110 " gl_TexCoord[0].xy = attrib1;\n"
111 " gl_Position = vec4(attrib0.x, attrib0.y, 0.0f, 1.0f);\n"
112 " }\n"
113};
114
115static const GLchar fetchYUY2Source[] =
116{
117 " vec4 fetchYUV(vec4 texColor)\n"
118 " {\n"
119 " return vec4(texColor.b, texColor.g, texColor.r, texColor.a);\n"
120 " }\n"
121};
122
123static const GLchar fetchUYVYSource[] =
124{
125 " vec4 fetchYUV(vec4 texColor)\n"
126 " {\n"
127 " return vec4(texColor.g, texColor.b, texColor.a, texColor.r);\n"
128 " }\n"
129};
130
131static const GLchar YUV2RGBShaderSource[] =
132{
133 " uniform sampler2D sSourceTex;\n"
134 " uniform vec4 uTexInfo;\n"
135 " \n"
136 " const mat3 yuvCoeffs = mat3\n"
137 " (\n"
138 " 1.164383f, 0.0f, 1.596027f, // first column \n"
139 " 1.164383f, -0.391762f, -0.812968f, // second column\n"
140 " 1.164383f, 2.017232f, 0.0f // third column\n"
141 " );\n"
142 " \n"
143 " void main() {\n"
144 " // Input texcoords are in [0;1] range for the target.\n"
145 " vec2 texCoord = gl_TexCoord[0].xy;\n"
146 " // Convert to the target coords in pixels: xPixel = texCoord.x * TextureWidth. \n"
147 " float xTargetPixel = texCoord.x * uTexInfo.x;\n"
148 " // Source texture is half width, i.e. it contains data in pixels [0; width / 2 - 1].\n"
149 " float xSourcePixel = xTargetPixel / 2.0f;\n"
150 " // Remainder is about 0.25 for even pixels and about 0.75 for odd pixels.\n"
151 " float remainder = fract(xSourcePixel);\n"
152 " // Back to the normalized coords: texCoord.x = xPixel / Width.\n"
153 " texCoord.x = xSourcePixel * uTexInfo.z;\n"
154 " vec4 texColor = texture2D(sSourceTex, texCoord);\n"
155 " vec4 y0uy1v = fetchYUV(texColor);\n"
156 " // Get y0 for even x coordinates and y1 for odd ones.\n"
157 " float y = remainder < 0.5f ? y0uy1v.x : y0uy1v.z;\n"
158 " // Make a vector for easier calculation.\n"
159 " vec3 yuv = vec3(y, y0uy1v.y, y0uy1v.w);\n"
160 " yuv -= vec3(0.0627f, 0.502f, 0.502f);\n"
161 " vec3 bgr = yuv * yuvCoeffs;\n"
162 " //vec3 bgr;\n"
163 " //bgr.r = 1.164383 * yuv.x + 1.596027 * yuv.z;\n"
164 " //bgr.g = 1.164383 * yuv.x - 0.391762 * yuv.y - 0.812968 * yuv.z;\n"
165 " //bgr.b = 1.164383 * yuv.x + 2.017232 * yuv.y;\n"
166 " bgr = clamp(bgr, 0.0f, 1.0f);\n"
167 " gl_FragData[0] = vec4(bgr, 1.0f);\n"
168 " }\n"
169};
170
171static const GLchar storeYUY2Source[] =
172{
173 " vec4 storeYUV(float y0, float u, float y1, float v)\n"
174 " {\n"
175 " return vec4(y1, u, y0, v);\n"
176 " }\n"
177};
178
179static const GLchar storeUYVYSource[] =
180{
181 " vec4 storeYUV(float y0, float u, float y1, float v)\n"
182 " {\n"
183 " return vec4(u, y1, v, y0);\n"
184 " }\n"
185};
186
187static const GLchar RGB2YUVShaderSource[] =
188{
189 " uniform sampler2D sSourceTex;\n"
190 " uniform vec4 uTexInfo;\n"
191 " \n"
192 " const mat3 bgrCoeffs = mat3\n"
193 " (\n"
194 " 0.2578f, 0.5039f, 0.0977f, // first column \n"
195 " -0.1484f, -0.2891f, 0.4375f, // second column\n"
196 " 0.4375f, -0.3672f, -0.0703f // third column\n"
197 " );\n"
198 " const vec3 yuvShift = vec3(0.0647f, 0.5039f, 0.5039f);\n"
199 " \n"
200 " void main() {\n"
201 " // Input texcoords are in [0;1] range for the target.\n"
202 " vec2 texCoordDst = gl_TexCoord[0].xy;\n"
203 " // Convert to the target coords in pixels: xPixel = TexCoord.x * TextureWidth.\n"
204 " float xTargetPixel = texCoordDst.x * uTexInfo.x;\n"
205 " vec4 bgraOutputPixel;\n"
206 " if (xTargetPixel < uTexInfo.x / 2.0f)\n"
207 " {\n"
208 " // Target texture is half width, i.e. it contains data in pixels [0; width / 2 - 1].\n"
209 " // Compute the source texture coords for the pixels which will be used to compute the target pixel.\n"
210 " vec2 texCoordSrc = texCoordDst;\n"
211 " texCoordSrc.x *= 2.0f;\n"
212 " // Even pixel. Fetch two BGRA source pixels.\n"
213 " vec4 texColor0 = texture2D(sSourceTex, texCoordSrc);\n"
214 " // Advance one pixel (+ 1/Width)\n"
215 " texCoordSrc.x += uTexInfo.z;\n"
216 " vec4 texColor1 = texture2D(sSourceTex, texCoordSrc);\n"
217 " vec3 yuv0 = texColor0.rgb * bgrCoeffs;\n"
218 " yuv0 += yuvShift;\n"
219 " vec3 yuv1 = texColor1.rgb * bgrCoeffs;\n"
220 " yuv1 += yuvShift;\n"
221 " float y0 = yuv0.r;\n"
222 " float u = (yuv0.g + yuv1.g) / 2.0f;\n"
223 " float y1 = yuv1.r;\n"
224 " float v = (yuv0.b + yuv1.b) / 2.0f;\n"
225 " bgraOutputPixel = storeYUV(y0, u, y1, v);\n"
226 " }\n"
227 " else\n"
228 " {\n"
229 " // [width / 2; width - 1] pixels are not used. Set to something.\n"
230 " bgraOutputPixel = vec4(0.0f, 0.0f, 0.0f, 0.0f);\n"
231 " }\n"
232 " bgraOutputPixel = clamp(bgraOutputPixel, 0.0f, 1.0f);\n"
233 " gl_FragData[0] = bgraOutputPixel;\n"
234 " }\n"
235};
236
237#define GL_CHECK_ERROR() do { \
238 VMSVGA3D_CHECK_LAST_ERROR_WARN(pState, pContext); \
239 if (pContext->lastError != GL_NO_ERROR) \
240 LogRelMax(10, ("VMSVGA: %s (%d): GL error 0x%x\n", __FUNCTION__, __LINE__, pContext->lastError)); \
241} while (0)
242
243/* Compile shaders and link a shader program. */
244static void createShaderProgram(PVMSVGA3DSTATE pState,
245 ShaderProgram *pProgram,
246 int cVertexSources, const GLchar **apszVertexSources,
247 int cFragmentSources, const GLchar **apszFragmentSources)
248{
249 AssertReturnVoid(pState->idActiveContext == VMSVGA3D_SHARED_CTX_ID);
250
251 /* Everything is done on the shared context. The pState and pContext are for GL_CHECK_ERROR macro. */
252 PVMSVGA3DCONTEXT pContext = &pState->SharedCtx;
253
254 int success;
255 char szInfoLog[1024];
256
257 /*
258 * VERTEX shader.
259 */
260 pProgram->vertexShader = pState->ext.glCreateShader(GL_VERTEX_SHADER);
261 GL_CHECK_ERROR();
262
263 pState->ext.glShaderSource(pProgram->vertexShader, cVertexSources, apszVertexSources, NULL);
264 GL_CHECK_ERROR();
265
266 pState->ext.glCompileShader(pProgram->vertexShader);
267 GL_CHECK_ERROR();
268
269 pState->ext.glGetShaderiv(pProgram->vertexShader, GL_COMPILE_STATUS, &success);
270 GL_CHECK_ERROR();
271 if (!success)
272 {
273 pState->ext.glGetShaderInfoLog(pProgram->vertexShader, sizeof(szInfoLog), NULL, szInfoLog);
274 GL_CHECK_ERROR();
275 LogRelMax(10, ("VMSVGA: Vertex shader compilation error:\n%s\n", szInfoLog));
276 };
277
278 /*
279 * FRAGMENT shader.
280 */
281 pProgram->fragmentShader = pState->ext.glCreateShader(GL_FRAGMENT_SHADER);
282 GL_CHECK_ERROR();
283
284 pState->ext.glShaderSource(pProgram->fragmentShader, cFragmentSources, apszFragmentSources, NULL);
285 GL_CHECK_ERROR();
286
287 pState->ext.glCompileShader(pProgram->fragmentShader);
288 GL_CHECK_ERROR();
289
290 pState->ext.glGetShaderiv(pProgram->fragmentShader, GL_COMPILE_STATUS, &success);
291 GL_CHECK_ERROR();
292 if (!success)
293 {
294 pState->ext.glGetShaderInfoLog(pProgram->fragmentShader, sizeof(szInfoLog), NULL, szInfoLog);
295 GL_CHECK_ERROR();
296 LogRelMax(10, ("VMSVGA: Fragment shader compilation error:\n%s\n", szInfoLog));
297 };
298
299 /*
300 * Program
301 */
302 pProgram->program = pState->ext.glCreateProgram();
303 GL_CHECK_ERROR();
304
305 pState->ext.glAttachShader(pProgram->program, pProgram->vertexShader);
306 GL_CHECK_ERROR();
307
308 pState->ext.glAttachShader(pProgram->program, pProgram->fragmentShader);
309 GL_CHECK_ERROR();
310
311 pState->ext.glLinkProgram(pProgram->program);
312 GL_CHECK_ERROR();
313
314 pState->ext.glGetProgramiv(pProgram->program, GL_LINK_STATUS, &success);
315 if(!success)
316 {
317 pState->ext.glGetProgramInfoLog(pProgram->program, sizeof(szInfoLog), NULL, szInfoLog);
318 GL_CHECK_ERROR();
319 LogRelMax(10, ("VMSVGA: Shader program link error:\n%s\n", szInfoLog));
320 }
321
322 pProgram->sSourceTex = pState->ext.glGetUniformLocation(pProgram->program, "sSourceTex");
323 GL_CHECK_ERROR();
324
325 pProgram->uTexInfo = pState->ext.glGetUniformLocation(pProgram->program, "uTexInfo");
326 GL_CHECK_ERROR();
327}
328
329/* Delete a shader program and associated shaders. */
330static void deleteShaderProgram(PVMSVGA3DSTATE pState,
331 ShaderProgram *pProgram)
332{
333 AssertReturnVoid(pState->idActiveContext == VMSVGA3D_SHARED_CTX_ID);
334
335 /* Everything is done on the shared context. The pState and pContext are for GL_CHECK_ERROR macro. */
336 PVMSVGA3DCONTEXT pContext = &pState->SharedCtx;
337
338 if (pProgram->program)
339 {
340 if (pProgram->vertexShader)
341 {
342 pState->ext.glDetachShader(pProgram->program, pProgram->vertexShader);
343 GL_CHECK_ERROR();
344
345 pState->ext.glDeleteShader(pProgram->vertexShader);
346 GL_CHECK_ERROR();
347 }
348
349 if (pProgram->fragmentShader)
350 {
351 pState->ext.glDetachShader(pProgram->program, pProgram->fragmentShader);
352 GL_CHECK_ERROR();
353
354 pState->ext.glDeleteShader(pProgram->fragmentShader);
355 GL_CHECK_ERROR();
356 }
357
358 pState->ext.glDeleteProgram(pProgram->program);
359 GL_CHECK_ERROR();
360 }
361
362 RT_ZERO(*pProgram);
363}
364
365/* Initialize the format conversion. Allocate and create necessary resources. */
366static void formatConversionInit(PVMSVGA3DSTATE pState)
367{
368 AssertReturnVoid(pState->idActiveContext == VMSVGA3D_SHARED_CTX_ID);
369
370 PVMSVGA3DFORMATCONVERTER pConv = pState->pConv;
371 AssertReturnVoid(pConv);
372
373 /* The pState and pContext variables are for GL_CHECK_ERROR macro. */
374 PVMSVGA3DCONTEXT pContext = &pState->SharedCtx;
375
376 pConv->pState = pState;
377
378 /*
379 * Shader programs.
380 */
381 static const GLchar *apszVertexShaderSources[] =
382 {
383 shaderHeaderSource,
384 vertexShaderSource
385 };
386
387 static const GLchar * apszYUY2ToRGBSources[] =
388 {
389 shaderHeaderSource,
390 fetchYUY2Source,
391 YUV2RGBShaderSource
392 };
393
394 static const GLchar *apszUYVYToRGBSources[] =
395 {
396 shaderHeaderSource,
397 fetchUYVYSource,
398 YUV2RGBShaderSource
399 };
400
401 static const GLchar *apszYUY2FromRGBSources[] =
402 {
403 shaderHeaderSource,
404 storeYUY2Source,
405 RGB2YUVShaderSource
406 };
407
408 static const GLchar *apszUYVYFromRGBSources[] =
409 {
410 shaderHeaderSource,
411 storeUYVYSource,
412 RGB2YUVShaderSource
413 };
414
415 createShaderProgram(pState, &pConv->programYUY2ToRGB,
416 RT_ELEMENTS(apszVertexShaderSources), apszVertexShaderSources,
417 RT_ELEMENTS(apszYUY2ToRGBSources), apszYUY2ToRGBSources);
418
419 createShaderProgram(pState, &pConv->programUYVYToRGB,
420 RT_ELEMENTS(apszVertexShaderSources), apszVertexShaderSources,
421 RT_ELEMENTS(apszUYVYToRGBSources), apszUYVYToRGBSources);
422
423 createShaderProgram(pState, &pConv->programYUY2FromRGB,
424 RT_ELEMENTS(apszVertexShaderSources), apszVertexShaderSources,
425 RT_ELEMENTS(apszYUY2FromRGBSources), apszYUY2FromRGBSources);
426
427 createShaderProgram(pState, &pConv->programUYVYFromRGB,
428 RT_ELEMENTS(apszVertexShaderSources), apszVertexShaderSources,
429 RT_ELEMENTS(apszUYVYFromRGBSources), apszUYVYFromRGBSources);
430
431 /*
432 * Create a framebuffer object which is used for rendering to a texture.
433 */
434 pState->ext.glGenFramebuffers(1, &pConv->framebuffer);
435 GL_CHECK_ERROR();
436
437 pState->ext.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, pConv->framebuffer);
438 GL_CHECK_ERROR();
439
440 static GLenum aDrawBuffers[] = { GL_COLOR_ATTACHMENT0 };
441 pState->ext.glDrawBuffers(RT_ELEMENTS(aDrawBuffers), aDrawBuffers);
442 GL_CHECK_ERROR();
443
444 pState->ext.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
445 GL_CHECK_ERROR();
446
447 /*
448 * Vertex attribute array.
449 */
450 pState->ext.glGenBuffers(1, &pConv->vertexBuffer);
451 GL_CHECK_ERROR();
452
453 pState->ext.glBindBuffer(GL_ARRAY_BUFFER, pConv->vertexBuffer);
454 GL_CHECK_ERROR();
455
456 pState->ext.glBufferData(GL_ARRAY_BUFFER, sizeof(aAttribData), aAttribData, GL_STATIC_DRAW);
457 GL_CHECK_ERROR();
458
459 pState->ext.glBindBuffer(GL_ARRAY_BUFFER, 0);
460 GL_CHECK_ERROR();
461}
462
463/* Delete everything. */
464static void formatConversionDestroy(PVMSVGA3DSTATE pState)
465{
466 AssertReturnVoid(pState->idActiveContext == VMSVGA3D_SHARED_CTX_ID);
467
468 PVMSVGA3DFORMATCONVERTER pConv = pState->pConv;
469 AssertReturnVoid(pConv);
470
471 /* The pState and pContext variables are for GL_CHECK_ERROR macro. */
472 PVMSVGA3DCONTEXT pContext = &pState->SharedCtx;
473
474 if (pConv->framebuffer != 0)
475 {
476 /* The code keeps nothing attached. */
477 pState->ext.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, pConv->framebuffer);
478 GL_CHECK_ERROR();
479
480 GLint texture = -1;
481 pState->ext.glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
482 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &texture);
483 GL_CHECK_ERROR();
484 AssertMsg(texture == 0, ("texture %d\n", texture));
485
486 pState->ext.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
487 GL_CHECK_ERROR();
488
489 pState->ext.glDeleteFramebuffers(1, &pConv->framebuffer);
490 GL_CHECK_ERROR();
491
492 pConv->framebuffer = 0;
493 }
494
495 deleteShaderProgram(pState, &pConv->programUYVYFromRGB);
496 deleteShaderProgram(pState, &pConv->programYUY2FromRGB);
497 deleteShaderProgram(pState, &pConv->programUYVYToRGB);
498 deleteShaderProgram(pState, &pConv->programYUY2ToRGB);
499
500 if (pConv->vertexBuffer)
501 {
502 pState->ext.glDeleteBuffers(1, &pConv->vertexBuffer);
503 GL_CHECK_ERROR();
504
505 pConv->vertexBuffer = 0;
506 }
507
508 pConv->pState = 0;
509}
510
511/* Make use of a shader program for the current context and initialize the program uniforms. */
512static void setShaderProgram(PVMSVGA3DSTATE pState,
513 ShaderProgram *pProgram,
514 uint32_t cWidth,
515 uint32_t cHeight)
516{
517 AssertReturnVoid(pState->idActiveContext == VMSVGA3D_SHARED_CTX_ID);
518
519 /* Everything is done on the shared context. The pState and pContext are for GL_CHECK_ERROR macro. */
520 PVMSVGA3DCONTEXT pContext = &pState->SharedCtx;
521
522 pState->ext.glUseProgram(pProgram->program);
523 GL_CHECK_ERROR();
524
525 pState->ext.glUniform1i(pProgram->sSourceTex, 0);
526 GL_CHECK_ERROR();
527
528 float aTextureInfo[4];
529 aTextureInfo[0] = (float)cWidth;
530 aTextureInfo[1] = (float)cHeight;
531 aTextureInfo[2] = 1.0f / (float)cWidth; /* Pixel width in texture coords. */
532 aTextureInfo[3] = 1.0f / (float)cHeight; /* Pixel height in texture coords. */
533
534 pState->ext.glUniform4fv(pProgram->uTexInfo, 1, aTextureInfo);
535 GL_CHECK_ERROR();
536}
537
538/* Attach the texture which must be used as the render target
539 * to the GL_DRAW_FRAMEBUFFER as GL_COLOR_ATTACHMENT0.
540 */
541static void setRenderTarget(PVMSVGA3DSTATE pState,
542 GLuint texture,
543 uint32_t iMipmap)
544{
545 AssertReturnVoid(pState->idActiveContext == VMSVGA3D_SHARED_CTX_ID);
546
547 PVMSVGA3DFORMATCONVERTER pConv = pState->pConv;
548 AssertReturnVoid(pConv);
549
550 /* Everything is done on the shared context. The pState and pContext are for GL_CHECK_ERROR macro. */
551 PVMSVGA3DCONTEXT pContext = &pState->SharedCtx;
552
553 pState->ext.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, pConv->framebuffer);
554 GL_CHECK_ERROR();
555
556 glBindTexture(GL_TEXTURE_2D, texture);
557 GL_CHECK_ERROR();
558
559 pState->ext.glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, iMipmap);
560 GL_CHECK_ERROR();
561
562 glBindTexture(GL_TEXTURE_2D, 0);
563 GL_CHECK_ERROR();
564
565 Assert(pState->ext.glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
566}
567
568/* Undo what setRenderTarget did. */
569static void unsetRenderTarget(PVMSVGA3DSTATE pState,
570 GLuint texture)
571{
572 AssertReturnVoid(pState->idActiveContext == VMSVGA3D_SHARED_CTX_ID);
573
574 /* Everything is done on the shared context. The pState and pContext are for GL_CHECK_ERROR macro. */
575 PVMSVGA3DCONTEXT pContext = &pState->SharedCtx;
576
577 RT_NOREF(texture);
578
579 pState->ext.glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
580 GL_CHECK_ERROR();
581
582 pState->ext.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
583 GL_CHECK_ERROR();
584}
585
586/** Convert one texture to another.
587 *
588 * @param pState The backend.
589 * @param pCurrentContext The current context, which must be restored before returning.
590 * @param pSurface The surface which needs conversion.
591 * @param iMipmap The mipmap level which needs to be converted.
592 * @param fToRGB True for conversion from the intermediate texture emulated format
593 * to the RGB format of the actual texture.
594 * False for conversion from the actual RGB texture to the intermediate texture.
595 */
596static void doRender(PVMSVGA3DSTATE pState,
597 PVMSVGA3DCONTEXT pCurrentContext,
598 PVMSVGA3DSURFACE pSurface,
599 uint32_t iMipmap,
600 bool fToRGB)
601{
602 if (!fToRGB)
603 {
604 /** @todo Disable readback transfers for now. They cause crash in glDrawArrays with Mesa 19.2 after
605 * a previously converted texture is deleted and another texture is being converted.
606 * Such transfer are useless anyway for the emulated YUV formats and the guest should not need them usually.
607 */
608 return;
609 }
610
611 LogFunc(("formatConversion: idActiveContext %u, pConv %p, sid=%u, oglid=%u, oglidEmul=%u, mm=%u, %s\n",
612 pState->idActiveContext, pState->pConv, pSurface->id, pSurface->oglId.texture, pSurface->idEmulated, iMipmap, fToRGB ? "ToRGB" : "FromRGB"));
613
614 PVMSVGA3DFORMATCONVERTER pConv = pState->pConv;
615 AssertReturnVoid(pConv);
616
617 ShaderProgram *pProgram = NULL;
618 GLuint sourceTexture = 0;
619 GLuint targetTexture = 0;
620 if (fToRGB)
621 {
622 if (pSurface->format == SVGA3D_YUY2)
623 {
624 pProgram = &pConv->programYUY2ToRGB;
625 }
626 else if (pSurface->format == SVGA3D_UYVY)
627 {
628 pProgram = &pConv->programUYVYToRGB;
629 }
630 sourceTexture = pSurface->idEmulated;
631 targetTexture = pSurface->oglId.texture;
632 }
633 else
634 {
635 if (pSurface->format == SVGA3D_YUY2)
636 {
637 pProgram = &pConv->programYUY2FromRGB;
638 }
639 else if (pSurface->format == SVGA3D_UYVY)
640 {
641 pProgram = &pConv->programUYVYFromRGB;
642 }
643 sourceTexture = pSurface->oglId.texture;
644 targetTexture = pSurface->idEmulated;
645 }
646
647 AssertReturnVoid(pProgram);
648
649 PVMSVGA3DMIPMAPLEVEL pMipmapLevel;
650 int rc = vmsvga3dMipmapLevel(pSurface, 0, iMipmap, &pMipmapLevel);
651 AssertRCReturnVoid(rc);
652
653 uint32_t const cWidth = pMipmapLevel->mipmapSize.width;
654 uint32_t const cHeight = pMipmapLevel->mipmapSize.height;
655
656 /* Use the shared context, where all textures are created. */
657 PVMSVGA3DCONTEXT pContext = &pState->SharedCtx;
658 VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
659
660 setShaderProgram(pState, pProgram, cWidth, cHeight);
661
662 setRenderTarget(pState, targetTexture, iMipmap);
663
664 glViewport(0, 0, cWidth, cHeight);
665 GL_CHECK_ERROR();
666
667 glDisable(GL_DEPTH_TEST);
668 GL_CHECK_ERROR();
669
670 pState->ext.glActiveTexture(GL_TEXTURE0);
671 GL_CHECK_ERROR();
672
673 glBindTexture(GL_TEXTURE_2D, sourceTexture);
674 GL_CHECK_ERROR();
675
676 /* Make sure to set the simplest filter. Otherwise the conversion will not work. */
677 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
678 GL_CHECK_ERROR();
679
680 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
681 GL_CHECK_ERROR();
682
683 pState->ext.glBindBuffer(GL_ARRAY_BUFFER, pConv->vertexBuffer);
684 GL_CHECK_ERROR();
685
686 GLuint index;
687 for (index = 0; index < RT_ELEMENTS(aVertexAttribs); ++index)
688 {
689 pState->ext.glEnableVertexAttribArray(index);
690 GL_CHECK_ERROR();
691
692 pState->ext.glVertexAttribPointer(index, aVertexAttribs[index].size, aVertexAttribs[index].type,
693 aVertexAttribs[index].normalized, aVertexAttribs[index].stride,
694 (const GLvoid *)(uintptr_t)aVertexAttribs[index].offset);
695 GL_CHECK_ERROR();
696 }
697
698 glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
699 GL_CHECK_ERROR();
700
701 pState->ext.glBindBuffer(GL_ARRAY_BUFFER, 0);
702 GL_CHECK_ERROR();
703
704 glBindTexture(GL_TEXTURE_2D, 0);
705 GL_CHECK_ERROR();
706
707 unsetRenderTarget(pState, targetTexture);
708
709 pState->ext.glUseProgram(0);
710 GL_CHECK_ERROR();
711
712 for (index = 0; index < RT_ELEMENTS(aVertexAttribs); ++index)
713 {
714 pState->ext.glDisableVertexAttribArray(index);
715 GL_CHECK_ERROR();
716 }
717
718 /* Restore the current context. */
719 VMSVGA3D_SET_CURRENT_CONTEXT(pState, pCurrentContext);
720}
721
722void FormatConvUpdateTexture(PVMSVGA3DSTATE pState,
723 PVMSVGA3DCONTEXT pCurrentContext,
724 PVMSVGA3DSURFACE pSurface,
725 uint32_t iMipmap)
726{
727 doRender(pState, pCurrentContext, pSurface, iMipmap, true);
728}
729
730void FormatConvReadTexture(PVMSVGA3DSTATE pState,
731 PVMSVGA3DCONTEXT pCurrentContext,
732 PVMSVGA3DSURFACE pSurface,
733 uint32_t iMipmap)
734{
735 doRender(pState, pCurrentContext, pSurface, iMipmap, false);
736}
737
738void vmsvga3dOnSharedContextDefine(PVMSVGA3DSTATE pState)
739{
740 /* Use the shared context, where all textures are created. */
741 PVMSVGA3DCONTEXT pContext = &pState->SharedCtx;
742 VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
743
744 /*
745 * Format conversion.
746 */
747 Assert(pState->pConv == NULL);
748
749 pState->pConv = (VMSVGA3DFORMATCONVERTER *)RTMemAllocZ(sizeof(VMSVGA3DFORMATCONVERTER));
750 AssertReturnVoid(pState->pConv);
751
752 formatConversionInit(pState);
753}
754
755void vmsvga3dOnSharedContextDestroy(PVMSVGA3DSTATE pState)
756{
757 /* Use the shared context, where all textures are created. */
758 PVMSVGA3DCONTEXT pContext = &pState->SharedCtx;
759 VMSVGA3D_SET_CURRENT_CONTEXT(pState, pContext);
760
761 if (pState->pConv)
762 {
763 formatConversionDestroy(pState);
764
765 RTMemFree(pState->pConv);
766 pState->pConv = NULL;
767 }
768}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use