VirtualBox

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

Last change on this file since 82096 was 82096, checked in by vboxsync, 5 years ago

Devices/Graphics: use appropriate texture id

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

© 2023 Oracle
ContactPrivacy policyTerms of Use