VirtualBox

source: vbox/trunk/src/VBox/GuestHost/OpenGL/state_tracker/state_glsl.c@ 46086

Last change on this file since 46086 was 45027, checked in by vboxsync, 12 years ago

crOpenGL: shader/program state fixes; glDrawXxx-based blitting fixes, etc.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.5 KB
Line 
1/* $Id: state_glsl.c 45027 2013-03-13 18:17:40Z vboxsync $ */
2
3/** @file
4 * VBox OpenGL: GLSL state tracking
5 */
6
7/*
8 * Copyright (C) 2009-2012 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#include "state.h"
20#include "state/cr_statetypes.h"
21#include "state/cr_statefuncs.h"
22#include "state_internals.h"
23#include "cr_mem.h"
24#include "cr_string.h"
25
26static CRGLSLShader* crStateGetShaderObj(GLuint id)
27{
28 CRContext *g = GetCurrentContext();
29
30 if (!g)
31 {
32 crWarning("crStateGetShaderObj called without current ctx");
33 }
34
35 return !g ? NULL : (CRGLSLShader *) crHashtableSearch(g->glsl.shaders, id);
36}
37
38static CRGLSLProgram* crStateGetProgramObj(GLuint id)
39{
40 CRContext *g = GetCurrentContext();
41
42 if (!g)
43 {
44 crWarning("crStateGetProgramObj called without current ctx");
45 }
46
47 return !g ? NULL : (CRGLSLProgram *) crHashtableSearch(g->glsl.programs, id);
48}
49
50static void crStateFreeGLSLShader(void *data)
51{
52 CRGLSLShader* pShader = (CRGLSLShader *) data;
53
54 if (pShader->source)
55 crFree(pShader->source);
56
57 crFree(pShader);
58}
59
60static void crStateFreeProgramAttribs(CRGLSLProgram* pProgram)
61{
62 GLuint i;
63
64 for (i=0; i<pProgram->activeState.cAttribs; ++i)
65 {
66 crFree(pProgram->activeState.pAttribs[i].name);
67 }
68
69 for (i=0; i<pProgram->currentState.cAttribs; ++i)
70 {
71 crFree(pProgram->currentState.pAttribs[i].name);
72 }
73
74 if (pProgram->activeState.pAttribs)
75 crFree(pProgram->activeState.pAttribs);
76
77 if (pProgram->currentState.pAttribs)
78 crFree(pProgram->currentState.pAttribs);
79}
80
81static void crStateFreeProgramUniforms(CRGLSLProgram* pProgram)
82{
83 GLuint i;
84
85 for (i=0; i<pProgram->cUniforms; ++i)
86 {
87 if (pProgram->pUniforms[i].name) crFree(pProgram->pUniforms[i].name);
88 if (pProgram->pUniforms[i].data) crFree(pProgram->pUniforms[i].data);
89 }
90
91 if (pProgram->pUniforms) crFree(pProgram->pUniforms);
92
93 pProgram->pUniforms = NULL;
94 pProgram->cUniforms = 0;
95
96#ifdef IN_GUEST
97 pProgram->bUniformsSynced = GL_FALSE;
98#endif
99}
100
101static void crStateShaderDecRefCount(void *data)
102{
103 CRGLSLShader *pShader = (CRGLSLShader *) data;
104
105 CRASSERT(pShader->refCount>0);
106
107 pShader->refCount--;
108
109 if (0==pShader->refCount && pShader->deleted)
110 {
111 CRContext *g = GetCurrentContext();
112 crHashtableDelete(g->glsl.shaders, pShader->id, crStateFreeGLSLShader);
113 }
114}
115
116static void crStateFakeDecRefCountCB(unsigned long key, void *data1, void *data2)
117{
118 CRGLSLShader *pShader = (CRGLSLShader *) data1;
119 CRContext *ctx = (CRContext*) data2;
120 CRGLSLShader *pRealShader;
121 (void) key;
122
123 pRealShader = crStateGetShaderObj(pShader->id);
124
125 if (pRealShader)
126 {
127 crStateShaderDecRefCount(pRealShader);
128 }
129 else
130 {
131 crWarning("crStateFakeDecRefCountCB: NULL pRealShader");
132 }
133}
134
135static void crStateFreeGLSLProgram(void *data)
136{
137 CRGLSLProgram* pProgram = (CRGLSLProgram *) data;
138
139 crFreeHashtable(pProgram->currentState.attachedShaders, crStateShaderDecRefCount);
140
141 if (pProgram->activeState.attachedShaders)
142 {
143 CRContext *g = GetCurrentContext();
144 crHashtableWalk(pProgram->activeState.attachedShaders, crStateFakeDecRefCountCB, g);
145 crFreeHashtable(pProgram->activeState.attachedShaders, crStateFreeGLSLShader);
146 }
147
148 crStateFreeProgramAttribs(pProgram);
149
150 crStateFreeProgramUniforms(pProgram);
151
152 crFree(pProgram);
153}
154
155DECLEXPORT(void) STATE_APIENTRY crStateGLSLInit(CRContext *ctx)
156{
157 ctx->glsl.shaders = crAllocHashtable();
158 ctx->glsl.programs = crAllocHashtable();
159 ctx->glsl.activeProgram = NULL;
160 ctx->glsl.bResyncNeeded = GL_FALSE;
161
162 if (!ctx->glsl.shaders || !ctx->glsl.programs)
163 {
164 crWarning("crStateGLSLInit: Out of memory!");
165 return;
166 }
167}
168
169DECLEXPORT(void) STATE_APIENTRY crStateGLSLDestroy(CRContext *ctx)
170{
171 CRContext *g = GetCurrentContext();
172
173 /*@todo: hack to allow crStateFreeGLSLProgram to work correctly,
174 as the current context isn't the one being destroyed*/
175#ifdef CHROMIUM_THREADSAFE
176 CRASSERT(g != ctx);
177 VBoxTlsRefAddRef(ctx); /* <- this is a hack to avoid subsequent SetCurrentContext(g) do recursive Destroy for ctx */
178 if (g)
179 VBoxTlsRefAddRef(g); /* <- ensure the g is not destroyed by the following SetCurrentContext call */
180 SetCurrentContext(ctx);
181#else
182 __currentContext = ctx;
183#endif
184
185 crFreeHashtable(ctx->glsl.programs, crStateFreeGLSLProgram);
186 crFreeHashtable(ctx->glsl.shaders, crStateFreeGLSLShader);
187
188#ifdef CHROMIUM_THREADSAFE
189 SetCurrentContext(g);
190 if (g)
191 VBoxTlsRefRelease(g);
192 VBoxTlsRefRelease(ctx); /* <- restore back the cRefs (see above) */
193#else
194 __currentContext = g;
195#endif
196
197}
198
199DECLEXPORT(GLuint) STATE_APIENTRY crStateGetShaderHWID(GLuint id)
200{
201 CRGLSLShader *pShader = crStateGetShaderObj(id);
202#ifdef IN_GUEST
203 CRASSERT(!pShader || pShader->hwid == id);
204#endif
205 return pShader ? pShader->hwid : 0;
206}
207
208DECLEXPORT(GLuint) STATE_APIENTRY crStateGetProgramHWID(GLuint id)
209{
210 CRGLSLProgram *pProgram = crStateGetProgramObj(id);
211#ifdef IN_GUEST
212 CRASSERT(!pProgram || pProgram->hwid == id);
213#endif
214 return pProgram ? pProgram->hwid : 0;
215}
216
217static void crStateCheckShaderHWIDCB(unsigned long key, void *data1, void *data2)
218{
219 CRGLSLShader *pShader = (CRGLSLShader *) data1;
220 crCheckIDHWID_t *pParms = (crCheckIDHWID_t*) data2;
221 (void) key;
222
223 if (pShader->hwid==pParms->hwid)
224 pParms->id = pShader->id;
225}
226
227static void crStateCheckProgramHWIDCB(unsigned long key, void *data1, void *data2)
228{
229 CRGLSLProgram *pProgram = (CRGLSLProgram *) data1;
230 crCheckIDHWID_t *pParms = (crCheckIDHWID_t*) data2;
231 (void) key;
232
233 if (pProgram->hwid==pParms->hwid)
234 pParms->id = pProgram->id;
235}
236
237DECLEXPORT(GLuint) STATE_APIENTRY crStateGLSLShaderHWIDtoID(GLuint hwid)
238{
239 CRContext *g = GetCurrentContext();
240 crCheckIDHWID_t parms;
241
242 parms.id = hwid;
243 parms.hwid = hwid;
244
245 crHashtableWalk(g->glsl.shaders, crStateCheckShaderHWIDCB, &parms);
246 return parms.id;
247}
248
249DECLEXPORT(GLuint) STATE_APIENTRY crStateGLSLProgramHWIDtoID(GLuint hwid)
250{
251 CRContext *g = GetCurrentContext();
252 crCheckIDHWID_t parms;
253
254 parms.id = hwid;
255 parms.hwid = hwid;
256
257 crHashtableWalk(g->glsl.programs, crStateCheckProgramHWIDCB, &parms);
258 return parms.id;
259}
260
261DECLEXPORT(GLuint) STATE_APIENTRY crStateDeleteObjectARB( GLhandleARB obj )
262{
263 GLuint hwId = crStateGetProgramHWID(obj);
264 if (hwId)
265 {
266 crStateDeleteProgram(obj);
267 }
268 else
269 {
270 hwId = crStateGetShaderHWID(obj);
271 crStateDeleteShader(obj);
272 }
273 return hwId;
274}
275
276DECLEXPORT(GLuint) STATE_APIENTRY crStateCreateShader(GLuint hwid, GLenum type)
277{
278 CRGLSLShader *pShader;
279 CRContext *g = GetCurrentContext();
280 GLuint stateId = hwid;
281
282#ifdef IN_GUEST
283 CRASSERT(!crStateGetShaderObj(stateId));
284#else
285 /* the proogram and shader names must not intersect because DeleteObjectARB must distinguish between them
286 * see crStateDeleteObjectARB
287 * this is why use programs table for shader keys allocation */
288 stateId = crHashtableAllocKeys(g->glsl.programs, 1);
289 if (!stateId)
290 {
291 crWarning("failed to allocate program key");
292 return 0;
293 }
294
295 /* the id may not necesserily be hwid after save state restoration */
296 while ((pShader = crStateGetShaderObj(stateId)) != NULL)
297 {
298 GLuint newStateId = stateId + 7;
299 crDebug("Shader object %d already exists, generating a new one, %d", stateId, newStateId);
300 stateId = newStateId;
301 }
302#endif
303
304 pShader = (CRGLSLShader *) crAlloc(sizeof(*pShader));
305 if (!pShader)
306 {
307 crWarning("crStateCreateShader: Out of memory!");
308 return 0;
309 }
310
311 pShader->id = stateId;
312 pShader->hwid = hwid;
313 pShader->type = type;
314 pShader->source = NULL;
315 pShader->compiled = GL_FALSE;
316 pShader->deleted = GL_FALSE;
317 pShader->refCount = 0;
318
319 crHashtableAdd(g->glsl.shaders, stateId, pShader);
320
321 return stateId;
322}
323
324DECLEXPORT(GLuint) STATE_APIENTRY crStateCreateProgram(GLuint hwid)
325{
326 CRGLSLProgram *pProgram;
327 CRContext *g = GetCurrentContext();
328 GLuint stateId = hwid;
329
330#ifdef IN_GUEST
331 pProgram = crStateGetProgramObj(stateId);
332 if (pProgram)
333 {
334 crWarning("Program object %d already exists!", stateId);
335 crStateDeleteProgram(stateId);
336 CRASSERT(!crStateGetProgramObj(stateId));
337 }
338#else
339 stateId = crHashtableAllocKeys(g->glsl.programs, 1);
340 if (!stateId)
341 {
342 crWarning("failed to allocate program key");
343 return 0;
344 }
345#endif
346
347 pProgram = (CRGLSLProgram *) crAlloc(sizeof(*pProgram));
348 if (!pProgram)
349 {
350 crWarning("crStateCreateProgram: Out of memory!");
351 return 0;
352 }
353
354 pProgram->id = stateId;
355 pProgram->hwid = hwid;
356 pProgram->validated = GL_FALSE;
357 pProgram->linked = GL_FALSE;
358 pProgram->deleted = GL_FALSE;
359 pProgram->activeState.attachedShaders = NULL;
360 pProgram->currentState.attachedShaders = crAllocHashtable();
361
362 pProgram->activeState.cAttribs = 0;
363 pProgram->activeState.pAttribs = NULL;
364 pProgram->currentState.cAttribs = 0;
365 pProgram->currentState.pAttribs = NULL;
366
367 pProgram->pUniforms = NULL;
368 pProgram->cUniforms = 0;
369#ifdef IN_GUEST
370 pProgram->bUniformsSynced = GL_FALSE;
371#endif
372
373 crHashtableAdd(g->glsl.programs, stateId, pProgram);
374
375 return stateId;
376}
377
378DECLEXPORT(void) STATE_APIENTRY crStateCompileShader(GLuint shader)
379{
380 CRGLSLShader *pShader = crStateGetShaderObj(shader);
381 if (!pShader)
382 {
383 crWarning("Unknown shader %d", shader);
384 return;
385 }
386
387 pShader->compiled = GL_TRUE;
388}
389
390static void crStateDbgCheckNoProgramOfId(void *data)
391{
392 crError("Unexpected Program id");
393}
394
395DECLEXPORT(void) STATE_APIENTRY crStateDeleteShader(GLuint shader)
396{
397 CRGLSLShader *pShader = crStateGetShaderObj(shader);
398 if (!pShader)
399 {
400 crWarning("Unknown shader %d", shader);
401 return;
402 }
403
404 pShader->deleted = GL_TRUE;
405
406 if (0==pShader->refCount)
407 {
408 CRContext *g = GetCurrentContext();
409 crHashtableDelete(g->glsl.shaders, shader, crStateFreeGLSLShader);
410 /* since we use programs table for key allocation key allocation, we need to
411 * free the key in the programs table.
412 * See comment in crStateCreateShader */
413 crHashtableDelete(g->glsl.programs, shader, crStateDbgCheckNoProgramOfId);
414 }
415}
416
417DECLEXPORT(void) STATE_APIENTRY crStateAttachShader(GLuint program, GLuint shader)
418{
419 CRGLSLProgram *pProgram = crStateGetProgramObj(program);
420 CRGLSLShader *pShader;
421
422 if (!pProgram)
423 {
424 crWarning("Unknown program %d", program);
425 return;
426 }
427
428 if (crHashtableSearch(pProgram->currentState.attachedShaders, shader))
429 {
430 /*shader already attached to this program*/
431 return;
432 }
433
434 pShader = crStateGetShaderObj(shader);
435
436 if (!pShader)
437 {
438 crWarning("Unknown shader %d", shader);
439 return;
440 }
441
442 pShader->refCount++;
443
444 crHashtableAdd(pProgram->currentState.attachedShaders, shader, pShader);
445}
446
447DECLEXPORT(void) STATE_APIENTRY crStateDetachShader(GLuint program, GLuint shader)
448{
449 CRGLSLProgram *pProgram = crStateGetProgramObj(program);
450 CRGLSLShader *pShader;
451
452 if (!pProgram)
453 {
454 crWarning("Unknown program %d", program);
455 return;
456 }
457
458 pShader = (CRGLSLShader *) crHashtableSearch(pProgram->currentState.attachedShaders, shader);
459 if (!pShader)
460 {
461 crWarning("Shader %d isn't attached to program %d", shader, program);
462 return;
463 }
464
465 crHashtableDelete(pProgram->currentState.attachedShaders, shader, NULL);
466
467 CRASSERT(pShader->refCount>0);
468 pShader->refCount--;
469
470 if (0==pShader->refCount)
471 {
472 CRContext *g = GetCurrentContext();
473 crHashtableDelete(g->glsl.shaders, shader, crStateFreeGLSLShader);
474 }
475}
476
477DECLEXPORT(void) STATE_APIENTRY crStateUseProgram(GLuint program)
478{
479 CRContext *g = GetCurrentContext();
480
481 if (program>0)
482 {
483 CRGLSLProgram *pProgram = crStateGetProgramObj(program);
484
485 if (!pProgram)
486 {
487 crWarning("Unknown program %d", program);
488 return;
489 }
490
491 g->glsl.activeProgram = pProgram;
492 }
493 else
494 {
495 g->glsl.activeProgram = NULL;
496 }
497}
498
499DECLEXPORT(void) STATE_APIENTRY crStateDeleteProgram(GLuint program)
500{
501 CRContext *g = GetCurrentContext();
502 CRGLSLProgram *pProgram = crStateGetProgramObj(program);
503
504 if (!pProgram)
505 {
506 crWarning("Unknown program %d", program);
507 return;
508 }
509
510 if (g->glsl.activeProgram == pProgram)
511 {
512 g->glsl.activeProgram = NULL;
513 }
514
515 crHashtableDelete(g->glsl.programs, program, crStateFreeGLSLProgram);
516}
517
518DECLEXPORT(void) STATE_APIENTRY crStateValidateProgram(GLuint program)
519{
520 CRGLSLProgram *pProgram = crStateGetProgramObj(program);
521
522 if (!pProgram)
523 {
524 crWarning("Unknown program %d", program);
525 return;
526 }
527
528 pProgram->validated = GL_TRUE;
529}
530
531static void crStateCopyShaderCB(unsigned long key, void *data1, void *data2)
532{
533 CRGLSLShader *pRealShader = (CRGLSLShader *) data1;
534 CRGLSLProgram *pProgram = (CRGLSLProgram *) data2;
535 CRGLSLShader *pShader;
536 GLint sLen=0;
537
538 CRASSERT(pRealShader);
539 pRealShader->refCount++;
540
541 pShader = (CRGLSLShader *) crAlloc(sizeof(*pShader));
542 if (!pShader)
543 {
544 crWarning("crStateCopyShaderCB: Out of memory!");
545 return;
546 }
547
548 crMemcpy(pShader, pRealShader, sizeof(*pShader));
549
550 diff_api.GetShaderiv(pShader->hwid, GL_SHADER_SOURCE_LENGTH, &sLen);
551 if (sLen>0)
552 {
553 pShader->source = (GLchar*) crAlloc(sLen);
554 diff_api.GetShaderSource(pShader->hwid, sLen, NULL, pShader->source);
555 }
556
557 crHashtableAdd(pProgram->activeState.attachedShaders, key, pShader);
558}
559
560DECLEXPORT(void) STATE_APIENTRY crStateLinkProgram(GLuint program)
561{
562 CRGLSLProgram *pProgram = crStateGetProgramObj(program);
563 GLuint i;
564
565 if (!pProgram)
566 {
567 crWarning("Unknown program %d", program);
568 return;
569 }
570
571 pProgram->linked = GL_TRUE;
572
573 /*Free program's active state*/
574 if (pProgram->activeState.attachedShaders)
575 {
576 crHashtableWalk(pProgram->activeState.attachedShaders, crStateFakeDecRefCountCB, NULL);
577 crFreeHashtable(pProgram->activeState.attachedShaders, crStateFreeGLSLShader);
578 pProgram->activeState.attachedShaders = NULL;
579 }
580 for (i=0; i<pProgram->activeState.cAttribs; ++i)
581 {
582 crFree(pProgram->activeState.pAttribs[i].name);
583 }
584 if (pProgram->activeState.pAttribs) crFree(pProgram->activeState.pAttribs);
585
586 /*copy current state to active state*/
587 crMemcpy(&pProgram->activeState, &pProgram->currentState, sizeof(CRGLSLProgramState));
588
589 pProgram->activeState.attachedShaders = crAllocHashtable();
590 if (!pProgram->activeState.attachedShaders)
591 {
592 crWarning("crStateLinkProgram: Out of memory!");
593 return;
594 }
595 crHashtableWalk(pProgram->currentState.attachedShaders, crStateCopyShaderCB, pProgram);
596
597 /*that's not a bug, note the memcpy above*/
598 if (pProgram->activeState.pAttribs)
599 {
600 pProgram->activeState.pAttribs = (CRGLSLAttrib *) crAlloc(pProgram->activeState.cAttribs * sizeof(CRGLSLAttrib));
601 }
602
603 for (i=0; i<pProgram->activeState.cAttribs; ++i)
604 {
605 crMemcpy(&pProgram->activeState.pAttribs[i], &pProgram->currentState.pAttribs[i], sizeof(CRGLSLAttrib));
606 pProgram->activeState.pAttribs[i].name = crStrdup(pProgram->currentState.pAttribs[i].name);
607 }
608
609 crStateFreeProgramUniforms(pProgram);
610}
611
612DECLEXPORT(void) STATE_APIENTRY crStateBindAttribLocation(GLuint program, GLuint index, const char * name)
613{
614 CRGLSLProgram *pProgram = crStateGetProgramObj(program);
615 GLuint i;
616 CRGLSLAttrib *pAttribs;
617
618 if (!pProgram)
619 {
620 crWarning("Unknown program %d", program);
621 return;
622 }
623
624 if (index>=CR_MAX_VERTEX_ATTRIBS)
625 {
626 crWarning("crStateBindAttribLocation: Index too big %d", index);
627 return;
628 }
629
630 for (i=0; i<pProgram->currentState.cAttribs; ++i)
631 {
632 if (!crStrcmp(pProgram->currentState.pAttribs[i].name, name))
633 {
634 crFree(pProgram->currentState.pAttribs[i].name);
635 pProgram->currentState.pAttribs[i].name = crStrdup(name);
636 return;
637 }
638 }
639
640 pAttribs = (CRGLSLAttrib*) crAlloc((pProgram->currentState.cAttribs+1)*sizeof(CRGLSLAttrib));
641 if (!pAttribs)
642 {
643 crWarning("crStateBindAttribLocation: Out of memory!");
644 return;
645 }
646
647 if (pProgram->currentState.cAttribs)
648 {
649 crMemcpy(&pAttribs[0], &pProgram->currentState.pAttribs[0], pProgram->currentState.cAttribs*sizeof(CRGLSLAttrib));
650 }
651 pAttribs[pProgram->currentState.cAttribs].index = index;
652 pAttribs[pProgram->currentState.cAttribs].name = crStrdup(name);
653
654 pProgram->currentState.cAttribs++;
655 if (pProgram->currentState.pAttribs) crFree(pProgram->currentState.pAttribs);
656 pProgram->currentState.pAttribs = pAttribs;
657}
658
659DECLEXPORT(GLint) STATE_APIENTRY crStateGetUniformSize(GLenum type)
660{
661 GLint size;
662
663 switch (type)
664 {
665 case GL_FLOAT:
666 size = 1;
667 break;
668 case GL_FLOAT_VEC2:
669 size = 2;
670 break;
671 case GL_FLOAT_VEC3:
672 size = 3;
673 break;
674 case GL_FLOAT_VEC4:
675 size = 4;
676 break;
677 case GL_INT:
678 size = 1;
679 break;
680 case GL_INT_VEC2:
681 size = 2;
682 break;
683 case GL_INT_VEC3:
684 size = 3;
685 break;
686 case GL_INT_VEC4:
687 size = 4;
688 break;
689 case GL_BOOL:
690 size = 1;
691 break;
692 case GL_BOOL_VEC2:
693 size = 2;
694 break;
695 case GL_BOOL_VEC3:
696 size = 3;
697 break;
698 case GL_BOOL_VEC4:
699 size = 4;
700 break;
701 case GL_FLOAT_MAT2:
702 size = 8;
703 break;
704 case GL_FLOAT_MAT3:
705 size = 12;
706 break;
707 case GL_FLOAT_MAT4:
708 size = 16;
709 break;
710 case GL_SAMPLER_1D:
711 case GL_SAMPLER_2D:
712 case GL_SAMPLER_3D:
713 case GL_SAMPLER_CUBE:
714 case GL_SAMPLER_1D_SHADOW:
715 case GL_SAMPLER_2D_SHADOW:
716 case GL_SAMPLER_2D_RECT_ARB:
717 case GL_SAMPLER_2D_RECT_SHADOW_ARB:
718 size = 1;
719 break;
720#ifdef CR_OPENGL_VERSION_2_1
721 case GL_FLOAT_MAT2x3:
722 size = 8;
723 break;
724 case GL_FLOAT_MAT2x4:
725 size = 8;
726 break;
727 case GL_FLOAT_MAT3x2:
728 size = 12;
729 break;
730 case GL_FLOAT_MAT3x4:
731 size = 12;
732 break;
733 case GL_FLOAT_MAT4x2:
734 size = 16;
735 break;
736 case GL_FLOAT_MAT4x3:
737 size = 16;
738 break;
739#endif
740 default:
741 crWarning("crStateGetUniformSize: unknown uniform type 0x%x", (GLint)type);
742 size = 16;
743 break;
744 }
745
746 return size;
747}
748
749DECLEXPORT(GLboolean) STATE_APIENTRY crStateIsIntUniform(GLenum type)
750{
751 if (GL_INT==type
752 || GL_INT_VEC2==type
753 || GL_INT_VEC3==type
754 || GL_INT_VEC4==type
755 || GL_BOOL==type
756 || GL_BOOL_VEC2==type
757 || GL_BOOL_VEC3==type
758 || GL_BOOL_VEC4==type
759 || GL_SAMPLER_1D==type
760 || GL_SAMPLER_2D==type
761 || GL_SAMPLER_3D==type
762 || GL_SAMPLER_CUBE==type
763 || GL_SAMPLER_1D_SHADOW==type
764 || GL_SAMPLER_2D_SHADOW==type
765 || GL_SAMPLER_2D_RECT_ARB==type
766 || GL_SAMPLER_2D_RECT_SHADOW_ARB==type)
767 {
768 return GL_TRUE;
769 }
770 else return GL_FALSE;
771}
772
773DECLEXPORT(GLboolean) STATE_APIENTRY crStateIsProgramUniformsCached(GLuint program)
774{
775 CRGLSLProgram *pProgram = crStateGetProgramObj(program);
776
777 if (!pProgram)
778 {
779 crWarning("Unknown program %d", program);
780 return GL_FALSE;
781 }
782
783#ifdef IN_GUEST
784 return pProgram->bUniformsSynced;
785#else
786 crWarning("crStateIsProgramUniformsCached called on host side!!");
787 return GL_FALSE;
788#endif
789}
790
791/*@todo: one of those functions should ignore uniforms starting with "gl"*/
792
793#ifdef IN_GUEST
794DECLEXPORT(void) STATE_APIENTRY
795crStateGLSLProgramCacheUniforms(GLuint program, GLsizei cbData, GLvoid *pData)
796{
797 CRGLSLProgram *pProgram = crStateGetProgramObj(program);
798 char *pCurrent = pData;
799 GLsizei cbRead, cbName;
800 GLuint i;
801
802 if (!pProgram)
803 {
804 crWarning("Unknown program %d", program);
805 return;
806 }
807
808 if (pProgram->bUniformsSynced)
809 {
810 crWarning("crStateGLSLProgramCacheUniforms: this shouldn't happen!");
811 crStateFreeProgramUniforms(pProgram);
812 }
813
814 if (cbData<sizeof(GLsizei))
815 {
816 crWarning("crStateGLSLProgramCacheUniforms: data too short");
817 return;
818 }
819
820 pProgram->cUniforms = ((GLsizei*)pCurrent)[0];
821 pCurrent += sizeof(GLsizei);
822 cbRead = sizeof(GLsizei);
823
824 crDebug("crStateGLSLProgramCacheUniforms: %i active uniforms", pProgram->cUniforms);
825
826 if (pProgram->cUniforms)
827 {
828 pProgram->pUniforms = crAlloc(pProgram->cUniforms*sizeof(CRGLSLUniform));
829 if (!pProgram->pUniforms)
830 {
831 crWarning("crStateGLSLProgramCacheUniforms: no memory");
832 pProgram->cUniforms = 0;
833 return;
834 }
835 }
836
837 for (i=0; i<pProgram->cUniforms; ++i)
838 {
839 cbRead += sizeof(GLuint)+sizeof(GLsizei);
840 if (cbRead>cbData)
841 {
842 crWarning("crStateGLSLProgramCacheUniforms: out of data reading uniform %i", i);
843 return;
844 }
845 pProgram->pUniforms[i].data = NULL;
846 pProgram->pUniforms[i].location = ((GLint*)pCurrent)[0];
847 pCurrent += sizeof(GLint);
848 cbName = ((GLsizei*)pCurrent)[0];
849 pCurrent += sizeof(GLsizei);
850
851 cbRead += cbName;
852 if (cbRead>cbData)
853 {
854 crWarning("crStateGLSLProgramCacheUniforms: out of data reading uniform's name %i", i);
855 return;
856 }
857
858 pProgram->pUniforms[i].name = crStrndup(pCurrent, cbName);
859 pCurrent += cbName;
860
861 crDebug("crStateGLSLProgramCacheUniforms: uniform[%i]=%d, %s", i, pProgram->pUniforms[i].location, pProgram->pUniforms[i].name);
862 }
863
864 pProgram->bUniformsSynced = GL_TRUE;
865
866 CRASSERT((pCurrent-((char*)pData))==cbRead);
867 CRASSERT(cbRead==cbData);
868}
869#else
870static GLboolean crStateGLSLProgramCacheOneUniform(GLuint location, GLsizei cbName, GLchar *pName,
871 char **pCurrent, GLsizei *pcbWritten, GLsizei maxcbData)
872{
873 *pcbWritten += sizeof(GLint)+sizeof(GLsizei)+cbName;
874 if (*pcbWritten>maxcbData)
875 {
876 crWarning("crStateGLSLProgramCacheUniforms: buffer too small");
877 crFree(pName);
878 return GL_FALSE;
879 }
880
881 crDebug("crStateGLSLProgramCacheUniforms: uniform[%i]=%s.", location, pName);
882
883 ((GLint*)*pCurrent)[0] = location;
884 *pCurrent += sizeof(GLint);
885 ((GLsizei*)*pCurrent)[0] = cbName;
886 *pCurrent += sizeof(GLsizei);
887 crMemcpy(*pCurrent, pName, cbName);
888 *pCurrent += cbName;
889
890 return GL_TRUE;
891}
892
893DECLEXPORT(void) STATE_APIENTRY
894crStateGLSLProgramCacheUniforms(GLuint program, GLsizei maxcbData, GLsizei *cbData, GLvoid *pData)
895{
896 CRGLSLProgram *pProgram = crStateGetProgramObj(program);
897 GLint maxUniformLen, activeUniforms=0, fakeUniformsCount, i, j;
898 char *pCurrent = pData;
899 GLsizei cbWritten;
900
901 if (!pProgram)
902 {
903 crWarning("Unknown program %d", program);
904 return;
905 }
906
907 diff_api.GetProgramiv(pProgram->hwid, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniformLen);
908 diff_api.GetProgramiv(pProgram->hwid, GL_ACTIVE_UNIFORMS, &activeUniforms);
909
910 *cbData = 0;
911
912 cbWritten = sizeof(GLsizei);
913 if (cbWritten>maxcbData)
914 {
915 crWarning("crStateGLSLProgramCacheUniforms: buffer too small");
916 return;
917 }
918 ((GLsizei*)pCurrent)[0] = activeUniforms;
919 fakeUniformsCount = activeUniforms;
920 pCurrent += sizeof(GLsizei);
921
922 crDebug("crStateGLSLProgramCacheUniforms: %i active uniforms", activeUniforms);
923
924 if (activeUniforms>0)
925 {
926 /*+8 to make sure our array uniforms with higher indices and [] will fit in as well*/
927 GLchar *name = (GLchar *) crAlloc(maxUniformLen+8);
928 GLenum type;
929 GLint size;
930 GLsizei cbName;
931 GLint location;
932
933 if (!name)
934 {
935 crWarning("crStateGLSLProgramCacheUniforms: no memory");
936 return;
937 }
938
939 for (i=0; i<activeUniforms; ++i)
940 {
941 diff_api.GetActiveUniform(pProgram->hwid, i, maxUniformLen, &cbName, &size, &type, name);
942 location = diff_api.GetUniformLocation(pProgram->hwid, name);
943
944 if (!crStateGLSLProgramCacheOneUniform(location, cbName, name, &pCurrent, &cbWritten, maxcbData))
945 return;
946
947 /* Only one active uniform variable will be reported for a uniform array by glGetActiveUniform,
948 * so we insert fake elements for other array elements.
949 */
950 if (size!=1)
951 {
952 char *pIndexStr = crStrchr(name, '[');
953 GLint firstIndex=1;
954 fakeUniformsCount += size;
955
956 crDebug("crStateGLSLProgramCacheUniforms: expanding array uniform, size=%i", size);
957
958 /*For array uniforms it's valid to query location of 1st element as both uniform and uniform[0].
959 *The name returned by glGetActiveUniform is driver dependent,
960 *atleast it's with [0] on win/ati and without [0] on linux/nvidia.
961 */
962 if (!pIndexStr)
963 {
964 pIndexStr = name+cbName;
965 firstIndex=0;
966 }
967 else
968 {
969 cbName = pIndexStr-name;
970 if (!crStateGLSLProgramCacheOneUniform(location, cbName, name, &pCurrent, &cbWritten, maxcbData))
971 return;
972 }
973
974 for (j=firstIndex; j<size; ++j)
975 {
976 sprintf(pIndexStr, "[%i]", j);
977 cbName = crStrlen(name);
978
979 location = diff_api.GetUniformLocation(pProgram->hwid, name);
980
981 if (!crStateGLSLProgramCacheOneUniform(location, cbName, name, &pCurrent, &cbWritten, maxcbData))
982 return;
983 }
984 }
985 }
986
987 crFree(name);
988 }
989
990 if (fakeUniformsCount!=activeUniforms)
991 {
992 ((GLsizei*)pData)[0] = fakeUniformsCount;
993 crDebug("FakeCount %i", fakeUniformsCount);
994 }
995
996 *cbData = cbWritten;
997
998 CRASSERT((pCurrent-((char*)pData))==cbWritten);
999}
1000#endif
1001
1002DECLEXPORT(GLint) STATE_APIENTRY crStateGetUniformLocation(GLuint program, const char * name)
1003{
1004#ifdef IN_GUEST
1005 CRGLSLProgram *pProgram = crStateGetProgramObj(program);
1006 GLint result=-1;
1007 GLuint i;
1008
1009 if (!pProgram)
1010 {
1011 crWarning("Unknown program %d", program);
1012 return -1;
1013 }
1014
1015 if (!pProgram->bUniformsSynced)
1016 {
1017 crWarning("crStateGetUniformLocation called for uncached uniforms");
1018 return -1;
1019 }
1020
1021 for (i=0; i<pProgram->cUniforms; ++i)
1022 {
1023 if (!crStrcmp(name, pProgram->pUniforms[i].name))
1024 {
1025 result = pProgram->pUniforms[i].location;
1026 break;
1027 }
1028 }
1029
1030 return result;
1031#else
1032 crWarning("crStateGetUniformLocation called on host side!!");
1033 return -1;
1034#endif
1035}
1036
1037static void crStateGLSLCreateShadersCB(unsigned long key, void *data1, void *data2)
1038{
1039 CRGLSLShader *pShader = (CRGLSLShader*) data1;
1040 CRContext *ctx = (CRContext *) data2;
1041
1042 pShader->hwid = diff_api.CreateShader(pShader->type);
1043}
1044
1045static void crStateFixAttachedShaderHWIDsCB(unsigned long key, void *data1, void *data2)
1046{
1047 CRGLSLShader *pShader = (CRGLSLShader*) data1;
1048 CRGLSLShader *pRealShader;
1049 CRContext *pCtx = (CRContext *) data2;
1050
1051 pRealShader = (CRGLSLShader *) crHashtableSearch(pCtx->glsl.shaders, key);
1052 CRASSERT(pRealShader);
1053
1054 pShader->hwid = pRealShader->hwid;
1055}
1056
1057static void crStateGLSLSyncShadersCB(unsigned long key, void *data1, void *data2)
1058{
1059 CRGLSLShader *pShader = (CRGLSLShader*) data1;
1060 (void) key;
1061 (void) data2;
1062
1063 if (pShader->source)
1064 {
1065 diff_api.ShaderSource(pShader->hwid, 1, (const char**)&pShader->source, NULL);
1066 if (pShader->compiled)
1067 diff_api.CompileShader(pShader->hwid);
1068 crFree(pShader->source);
1069 pShader->source = NULL;
1070 }
1071
1072 if (pShader->deleted)
1073 diff_api.DeleteShader(pShader->hwid);
1074}
1075
1076static void crStateAttachShaderCB(unsigned long key, void *data1, void *data2)
1077{
1078 CRGLSLShader *pShader = (CRGLSLShader*) data1;
1079 CRGLSLProgram *pProgram = (CRGLSLProgram *) data2;
1080 (void) key;
1081
1082 if (pShader->source)
1083 {
1084 diff_api.ShaderSource(pShader->hwid, 1, (const char**)&pShader->source, NULL);
1085 if (pShader->compiled)
1086 diff_api.CompileShader(pShader->hwid);
1087 }
1088
1089 diff_api.AttachShader(pProgram->hwid, pShader->hwid);
1090}
1091
1092static void crStateDetachShaderCB(unsigned long key, void *data1, void *data2)
1093{
1094 CRGLSLShader *pShader = (CRGLSLShader*) data1;
1095 CRGLSLProgram *pProgram = (CRGLSLProgram *) data2;
1096 (void) key;
1097
1098 diff_api.DetachShader(pProgram->hwid, pShader->hwid);
1099}
1100
1101static void crStateGLSLCreateProgramCB(unsigned long key, void *data1, void *data2)
1102{
1103 CRGLSLProgram *pProgram = (CRGLSLProgram*) data1;
1104 CRContext *ctx = (CRContext *) data2;
1105 GLuint i;
1106
1107 pProgram->hwid = diff_api.CreateProgram();
1108
1109 if (pProgram->linked)
1110 {
1111 CRASSERT(pProgram->activeState.attachedShaders);
1112
1113 crHashtableWalk(pProgram->activeState.attachedShaders, crStateFixAttachedShaderHWIDsCB, ctx);
1114 crHashtableWalk(pProgram->activeState.attachedShaders, crStateAttachShaderCB, pProgram);
1115
1116 for (i=0; i<pProgram->activeState.cAttribs; ++i)
1117 {
1118 diff_api.BindAttribLocation(pProgram->hwid, pProgram->activeState.pAttribs[i].index, pProgram->activeState.pAttribs[i].name);
1119 }
1120
1121 if (pProgram->validated)
1122 diff_api.ValidateProgram(pProgram->hwid);
1123
1124 diff_api.LinkProgram(pProgram->hwid);
1125 }
1126
1127 diff_api.UseProgram(pProgram->hwid);
1128
1129 for (i=0; i<pProgram->cUniforms; ++i)
1130 {
1131 GLint location;
1132 GLfloat *pFdata = (GLfloat*)pProgram->pUniforms[i].data;
1133 GLint *pIdata = (GLint*)pProgram->pUniforms[i].data;
1134
1135 location = diff_api.GetUniformLocation(pProgram->hwid, pProgram->pUniforms[i].name);
1136 switch (pProgram->pUniforms[i].type)
1137 {
1138 case GL_FLOAT:
1139 diff_api.Uniform1fv(location, 1, pFdata);
1140 break;
1141 case GL_FLOAT_VEC2:
1142 diff_api.Uniform2fv(location, 1, pFdata);
1143 break;
1144 case GL_FLOAT_VEC3:
1145 diff_api.Uniform3fv(location, 1, pFdata);
1146 break;
1147 case GL_FLOAT_VEC4:
1148 diff_api.Uniform4fv(location, 1, pFdata);
1149 break;
1150 case GL_INT:
1151 case GL_BOOL:
1152 diff_api.Uniform1iv(location, 1, pIdata);
1153 break;
1154 case GL_INT_VEC2:
1155 case GL_BOOL_VEC2:
1156 diff_api.Uniform2iv(location, 1, pIdata);
1157 break;
1158 case GL_INT_VEC3:
1159 case GL_BOOL_VEC3:
1160 diff_api.Uniform3iv(location, 1, pIdata);
1161 break;
1162 case GL_INT_VEC4:
1163 case GL_BOOL_VEC4:
1164 diff_api.Uniform4iv(location, 1, pIdata);
1165 break;
1166 case GL_FLOAT_MAT2:
1167 diff_api.UniformMatrix2fv(location, 1, GL_FALSE, pFdata);
1168 break;
1169 case GL_FLOAT_MAT3:
1170 diff_api.UniformMatrix3fv(location, 1, GL_FALSE, pFdata);
1171 break;
1172 case GL_FLOAT_MAT4:
1173 diff_api.UniformMatrix4fv(location, 1, GL_FALSE, pFdata);
1174 break;
1175 case GL_SAMPLER_1D:
1176 case GL_SAMPLER_2D:
1177 case GL_SAMPLER_3D:
1178 case GL_SAMPLER_CUBE:
1179 case GL_SAMPLER_1D_SHADOW:
1180 case GL_SAMPLER_2D_SHADOW:
1181 case GL_SAMPLER_2D_RECT_ARB:
1182 case GL_SAMPLER_2D_RECT_SHADOW_ARB:
1183 diff_api.Uniform1iv(location, 1, pIdata);
1184 break;
1185#ifdef CR_OPENGL_VERSION_2_1
1186 case GL_FLOAT_MAT2x3:
1187 diff_api.UniformMatrix2x3fv(location, 1, GL_FALSE, pFdata);
1188 break;
1189 case GL_FLOAT_MAT2x4:
1190 diff_api.UniformMatrix2x4fv(location, 1, GL_FALSE, pFdata);
1191 break;
1192 case GL_FLOAT_MAT3x2:
1193 diff_api.UniformMatrix3x2fv(location, 1, GL_FALSE, pFdata);
1194 break;
1195 case GL_FLOAT_MAT3x4:
1196 diff_api.UniformMatrix3x4fv(location, 1, GL_FALSE, pFdata);
1197 break;
1198 case GL_FLOAT_MAT4x2:
1199 diff_api.UniformMatrix4x2fv(location, 1, GL_FALSE, pFdata);
1200 break;
1201 case GL_FLOAT_MAT4x3:
1202 diff_api.UniformMatrix4x3fv(location, 1, GL_FALSE, pFdata);
1203 break;
1204#endif
1205 default:
1206 crWarning("crStateGLSLCreateProgramCB: unknown uniform type 0x%x", (GLint)pProgram->pUniforms[i].type);
1207 break;
1208 }
1209 crFree(pProgram->pUniforms[i].data);
1210 crFree(pProgram->pUniforms[i].name);
1211 } /*for (i=0; i<pProgram->cUniforms; ++i)*/
1212 if (pProgram->pUniforms) crFree(pProgram->pUniforms);
1213 pProgram->pUniforms = NULL;
1214 pProgram->cUniforms = 0;
1215
1216 crHashtableWalk(pProgram->activeState.attachedShaders, crStateDetachShaderCB, pProgram);
1217 crHashtableWalk(pProgram->currentState.attachedShaders, crStateAttachShaderCB, pProgram);
1218}
1219
1220DECLEXPORT(void) STATE_APIENTRY crStateGLSLSwitch(CRContext *from, CRContext *to)
1221{
1222 GLboolean fForceUseProgramSet = GL_FALSE;
1223 if (to->glsl.bResyncNeeded)
1224 {
1225 to->glsl.bResyncNeeded = GL_FALSE;
1226
1227 crHashtableWalk(to->glsl.shaders, crStateGLSLCreateShadersCB, to);
1228
1229 crHashtableWalk(to->glsl.programs, crStateGLSLCreateProgramCB, to);
1230
1231 /* crStateGLSLCreateProgramCB changes the current program, ensure we have the proper program re-sored */
1232 fForceUseProgramSet = GL_TRUE;
1233
1234 crHashtableWalk(to->glsl.shaders, crStateGLSLSyncShadersCB, NULL);
1235 }
1236
1237 if (to->glsl.activeProgram != from->glsl.activeProgram || fForceUseProgramSet)
1238 {
1239 diff_api.UseProgram(to->glsl.activeProgram ? to->glsl.activeProgram->hwid : 0);
1240 }
1241}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette