VirtualBox

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

Last change on this file since 82781 was 82240, checked in by vboxsync, 4 years ago

Devices/Graphics: OpenGL backend: simplified the color format conversion

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

© 2023 Oracle
ContactPrivacy policyTerms of Use