blob: 2c6944c7d456ebeada4ebdb96591328caec95b52 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// Context.cpp: Implements the gl::Context class, managing all GL state and performing
8// rendering operations. It is the GLES2 specific implementation of EGLContext.
9
10#include "Context.h"
11#include "main.h"
12#include "Display.h"
13#include "Buffer.h"
14#include "Shader.h"
15#include "Program.h"
16#include "Texture.h"
17#include "FrameBuffer.h"
18#include "RenderBuffer.h"
19#include "mathutil.h"
20#include "utilities.h"
21
22namespace gl
23{
24Array::Array()
25{
26 enabled = false;
27 boundBuffer = 0;
28 size = 4;
29 type = GL_FLOAT;
30 normalized = GL_FALSE;
31 stride = 0;
32 pointer = NULL;
33}
34
35Context::Context(const egl::Config *config) : mConfig(config)
36{
37 setClearColor(0.0f, 0.0f, 0.0f, 0.0f);
38 depthClearValue = 1.0f;
39 stencilClearValue = 0;
40
41 cullFace = false;
42 cullMode = GL_BACK;
43 frontFace = GL_CCW;
44 depthTest = false;
45 depthFunc = GL_LESS;
46 blend = false;
47 sourceBlendRGB = GL_ONE;
48 sourceBlendAlpha = GL_ONE;
49 destBlendRGB = GL_ZERO;
50 destBlendAlpha = GL_ZERO;
51 blendEquationRGB = GL_FUNC_ADD;
52 blendEquationAlpha = GL_FUNC_ADD;
53 blendColor.red = 0;
54 blendColor.green = 0;
55 blendColor.blue = 0;
56 blendColor.alpha = 0;
57 stencilTest = false;
58 stencilFunc = GL_ALWAYS;
59 stencilRef = 0;
60 stencilMask = -1;
61 stencilWritemask = -1;
62 stencilBackFunc = GL_ALWAYS;
63 stencilBackRef = 0;
64 stencilBackMask = - 1;
65 stencilBackWritemask = -1;
66 stencilFail = GL_KEEP;
67 stencilPassDepthFail = GL_KEEP;
68 stencilPassDepthPass = GL_KEEP;
69 stencilBackFail = GL_KEEP;
70 stencilBackPassDepthFail = GL_KEEP;
71 stencilBackPassDepthPass = GL_KEEP;
72 polygonOffsetFill = false;
73 sampleAlphaToCoverage = false;
74 sampleCoverage = false;
75 sampleCoverageValue = 1.0f;
76 sampleCoverageInvert = GL_FALSE;
77 scissorTest = false;
78 dither = true;
79
80 viewportX = 0;
81 viewportY = 0;
82 viewportWidth = config->mDisplayMode.Width;
83 viewportHeight = config->mDisplayMode.Height;
84 zNear = 0.0f;
85 zFar = 1.0f;
86
87 scissorX = 0;
88 scissorY = 0;
89 scissorWidth = config->mDisplayMode.Width;
90 scissorHeight = config->mDisplayMode.Height;
91
92 colorMaskRed = true;
93 colorMaskGreen = true;
94 colorMaskBlue = true;
95 colorMaskAlpha = true;
96 depthMask = true;
97
98 // [OpenGL ES 2.0.24] section 3.7 page 83:
99 // In the initial state, TEXTURE_2D and TEXTURE_CUBE_MAP have twodimensional
100 // and cube map texture state vectors respectively associated with them.
101 // In order that access to these initial textures not be lost, they are treated as texture
102 // objects all of whose names are 0.
103
104 mTexture2DZero = new Texture2D();
105 mTextureCubeMapZero = new TextureCubeMap();
106
107 mColorbufferZero = NULL;
108 mDepthbufferZero = NULL;
109 mStencilbufferZero = NULL;
110
111 activeSampler = 0;
112 arrayBuffer = 0;
113 elementArrayBuffer = 0;
114 bindTextureCubeMap(0);
115 bindTexture2D(0);
116 bindFramebuffer(0);
117 bindRenderbuffer(0);
118
119 for (int sampler = 0; sampler < MAX_TEXTURE_IMAGE_UNITS; sampler++)
120 {
121 samplerTexture[sampler] = 0;
122 }
123
124 currentProgram = 0;
125
126 mInvalidEnum = false;
127 mInvalidValue = false;
128 mInvalidOperation = false;
129 mOutOfMemory = false;
130 mInvalidFramebufferOperation = false;
131}
132
133Context::~Context()
134{
135 currentProgram = 0;
136
137 delete mTexture2DZero;
138 delete mTextureCubeMapZero;
139
140 delete mColorbufferZero;
141 delete mDepthbufferZero;
142 delete mStencilbufferZero;
143
144 while (!mBufferMap.empty())
145 {
146 deleteBuffer(mBufferMap.begin()->first);
147 }
148
149 while (!mProgramMap.empty())
150 {
151 deleteProgram(mProgramMap.begin()->first);
152 }
153
154 while (!mShaderMap.empty())
155 {
156 deleteShader(mShaderMap.begin()->first);
157 }
158
159 while (!mFramebufferMap.empty())
160 {
161 deleteFramebuffer(mFramebufferMap.begin()->first);
162 }
163
164 while (!mRenderbufferMap.empty())
165 {
166 deleteRenderbuffer(mRenderbufferMap.begin()->first);
167 }
168
169 while (!mTextureMap.empty())
170 {
171 deleteTexture(mTextureMap.begin()->first);
172 }
173}
174
175void Context::makeCurrent(egl::Display *display, egl::Surface *surface)
176{
177 IDirect3DDevice9 *device = display->getDevice();
178
179 // Wrap the existing Direct3D 9 resources into GL objects and assign them to the '0' names
180 IDirect3DSurface9 *defaultRenderTarget = surface->getRenderTarget();
181 IDirect3DSurface9 *defaultDepthStencil = NULL;
182 device->GetDepthStencilSurface(&defaultDepthStencil);
183
184 Framebuffer *framebufferZero = new Framebuffer();
185 Colorbuffer *colorbufferZero = new Colorbuffer(defaultRenderTarget);
186 Depthbuffer *depthbufferZero = new Depthbuffer(defaultDepthStencil);
187 Stencilbuffer *stencilbufferZero = new Stencilbuffer(defaultDepthStencil);
188
189 setFramebufferZero(framebufferZero);
190 setColorbufferZero(colorbufferZero);
191 setDepthbufferZero(depthbufferZero);
192 setStencilbufferZero(stencilbufferZero);
193
194 framebufferZero->setColorbuffer(GL_RENDERBUFFER, 0);
195 framebufferZero->setDepthbuffer(GL_RENDERBUFFER, 0);
196 framebufferZero->setStencilbuffer(GL_RENDERBUFFER, 0);
197
198 defaultRenderTarget->Release();
199
200 if (defaultDepthStencil)
201 {
202 defaultDepthStencil->Release();
203 }
204}
205
206void Context::setClearColor(float red, float green, float blue, float alpha)
207{
208 colorClearValue.red = red;
209 colorClearValue.green = green;
210 colorClearValue.blue = blue;
211 colorClearValue.alpha = alpha;
212}
213
214void Context::setClearDepth(float depth)
215{
216 depthClearValue = depth;
217}
218
219void Context::setClearStencil(int stencil)
220{
221 stencilClearValue = stencil;
222}
223
224// Returns an unused buffer name
225GLuint Context::createBuffer()
226{
227 unsigned int handle = 1;
228
229 while (mBufferMap.find(handle) != mBufferMap.end())
230 {
231 handle++;
232 }
233
234 mBufferMap[handle] = NULL;
235
236 return handle;
237}
238
239// Returns an unused shader/program name
240GLuint Context::createShader(GLenum type)
241{
242 unsigned int handle = 1;
243
244 while (mShaderMap.find(handle) != mShaderMap.end() || mProgramMap.find(handle) != mProgramMap.end()) // Shared name space
245 {
246 handle++;
247 }
248
249 if (type == GL_VERTEX_SHADER)
250 {
251 mShaderMap[handle] = new VertexShader();
252 }
253 else if (type == GL_FRAGMENT_SHADER)
254 {
255 mShaderMap[handle] = new FragmentShader();
256 }
257 else UNREACHABLE();
258
259 return handle;
260}
261
262// Returns an unused program/shader name
263GLuint Context::createProgram()
264{
265 unsigned int handle = 1;
266
267 while (mProgramMap.find(handle) != mProgramMap.end() || mShaderMap.find(handle) != mShaderMap.end()) // Shared name space
268 {
269 handle++;
270 }
271
272 mProgramMap[handle] = new Program();
273
274 return handle;
275}
276
277// Returns an unused texture name
278GLuint Context::createTexture()
279{
280 unsigned int handle = 1;
281
282 while (mTextureMap.find(handle) != mTextureMap.end())
283 {
284 handle++;
285 }
286
287 mTextureMap[handle] = NULL;
288
289 return handle;
290}
291
292// Returns an unused framebuffer name
293GLuint Context::createFramebuffer()
294{
295 unsigned int handle = 1;
296
297 while (mFramebufferMap.find(handle) != mFramebufferMap.end())
298 {
299 handle++;
300 }
301
302 mFramebufferMap[handle] = NULL;
303
304 return handle;
305}
306
307// Returns an unused renderbuffer name
308GLuint Context::createRenderbuffer()
309{
310 unsigned int handle = 1;
311
312 while(mRenderbufferMap.find(handle) != mRenderbufferMap.end())
313 {
314 handle++;
315 }
316
317 mRenderbufferMap[handle] = NULL;
318
319 return handle;
320}
321
322void Context::deleteBuffer(GLuint buffer)
323{
324 BufferMap::iterator bufferObject = mBufferMap.find(buffer);
325
326 if (bufferObject != mBufferMap.end())
327 {
328 detachBuffer(buffer);
329
330 delete bufferObject->second;
331 mBufferMap.erase(bufferObject);
332 }
333}
334
335void Context::deleteShader(GLuint shader)
336{
337 ShaderMap::iterator shaderObject = mShaderMap.find(shader);
338
339 if (shaderObject != mShaderMap.end())
340 {
341 if (!shaderObject->second->isAttached())
342 {
343 delete shaderObject->second;
344 mShaderMap.erase(shaderObject);
345 }
346 else
347 {
348 shaderObject->second->flagForDeletion();
349 }
350 }
351}
352
353void Context::deleteProgram(GLuint program)
354{
355 ProgramMap::iterator programObject = mProgramMap.find(program);
356
357 if (programObject != mProgramMap.end())
358 {
359 if (program != currentProgram)
360 {
361 delete programObject->second;
362 mProgramMap.erase(programObject);
363 }
364 else
365 {
366 programObject->second->flagForDeletion();
367 }
368 }
369}
370
371void Context::deleteTexture(GLuint texture)
372{
373 TextureMap::iterator textureObject = mTextureMap.find(texture);
374
375 if (textureObject != mTextureMap.end())
376 {
377 detachTexture(texture);
378
379 if (texture != 0)
380 {
381 delete textureObject->second;
382 }
383
384 mTextureMap.erase(textureObject);
385 }
386}
387
388void Context::deleteFramebuffer(GLuint framebuffer)
389{
390 FramebufferMap::iterator framebufferObject = mFramebufferMap.find(framebuffer);
391
392 if (framebufferObject != mFramebufferMap.end())
393 {
394 detachFramebuffer(framebuffer);
395
396 delete framebufferObject->second;
397 mFramebufferMap.erase(framebufferObject);
398 }
399}
400
401void Context::deleteRenderbuffer(GLuint renderbuffer)
402{
403 RenderbufferMap::iterator renderbufferObject = mRenderbufferMap.find(renderbuffer);
404
405 if (renderbufferObject != mRenderbufferMap.end())
406 {
407 detachRenderbuffer(renderbuffer);
408
409 delete renderbufferObject->second;
410 mRenderbufferMap.erase(renderbufferObject);
411 }
412}
413
414void Context::bindArrayBuffer(unsigned int buffer)
415{
416 if (buffer != 0 && !getBuffer(buffer))
417 {
418 mBufferMap[buffer] = new Buffer();
419 }
420
421 arrayBuffer = buffer;
422}
423
424void Context::bindElementArrayBuffer(unsigned int buffer)
425{
426 if (buffer != 0 && !getBuffer(buffer))
427 {
428 mBufferMap[buffer] = new Buffer();
429 }
430
431 elementArrayBuffer = buffer;
432}
433
434void Context::bindTexture2D(GLuint texture)
435{
436 if (!getTexture(texture) || texture == 0)
437 {
438 if (texture != 0)
439 {
440 mTextureMap[texture] = new Texture2D();
441 }
442 else // Special case: 0 refers to different initial textures based on the target
443 {
444 mTextureMap[0] = mTexture2DZero;
445 }
446 }
447
448 texture2D = texture;
449
450 samplerTexture[activeSampler] = texture;
451}
452
453void Context::bindTextureCubeMap(GLuint texture)
454{
455 if (!getTexture(texture) || texture == 0)
456 {
457 if (texture != 0)
458 {
459 mTextureMap[texture] = new TextureCubeMap();
460 }
461 else // Special case: 0 refers to different initial textures based on the target
462 {
463 mTextureMap[0] = mTextureCubeMapZero;
464 }
465 }
466
467 textureCubeMap = texture;
468
469 samplerTexture[activeSampler] = texture;
470}
471
472void Context::bindFramebuffer(GLuint framebuffer)
473{
474 if (!getFramebuffer(framebuffer))
475 {
476 mFramebufferMap[framebuffer] = new Framebuffer();
477 }
478
479 this->framebuffer = framebuffer;
480}
481
482void Context::bindRenderbuffer(GLuint renderbuffer)
483{
484 if (renderbuffer != 0 && !getRenderbuffer(renderbuffer))
485 {
486 mRenderbufferMap[renderbuffer] = new Renderbuffer();
487 }
488
489 this->renderbuffer = renderbuffer;
490}
491
492void Context::useProgram(GLuint program)
493{
494 Program *programObject = getCurrentProgram();
495
496 if (programObject && programObject->isFlaggedForDeletion())
497 {
498 deleteProgram(currentProgram);
499 }
500
501 currentProgram = program;
502}
503
504void Context::setFramebufferZero(Framebuffer *buffer)
505{
506 delete mFramebufferMap[0];
507 mFramebufferMap[0] = buffer;
508}
509
510void Context::setColorbufferZero(Colorbuffer *buffer)
511{
512 delete mColorbufferZero;
513 mColorbufferZero = buffer;
514}
515
516void Context::setDepthbufferZero(Depthbuffer *buffer)
517{
518 delete mDepthbufferZero;
519 mDepthbufferZero = buffer;
520}
521
522void Context::setStencilbufferZero(Stencilbuffer *buffer)
523{
524 delete mStencilbufferZero;
525 mStencilbufferZero = buffer;
526}
527
528void Context::setRenderbuffer(Renderbuffer *buffer)
529{
530 delete mRenderbufferMap[renderbuffer];
531 mRenderbufferMap[renderbuffer] = buffer;
532}
533
534Buffer *Context::getBuffer(unsigned int handle)
535{
536 BufferMap::iterator buffer = mBufferMap.find(handle);
537
538 if (buffer == mBufferMap.end())
539 {
540 return NULL;
541 }
542 else
543 {
544 return buffer->second;
545 }
546}
547
548Shader *Context::getShader(unsigned int handle)
549{
550 ShaderMap::iterator shader = mShaderMap.find(handle);
551
552 if (shader == mShaderMap.end())
553 {
554 return NULL;
555 }
556 else
557 {
558 return shader->second;
559 }
560}
561
562Program *Context::getProgram(unsigned int handle)
563{
564 ProgramMap::iterator program = mProgramMap.find(handle);
565
566 if (program == mProgramMap.end())
567 {
568 return NULL;
569 }
570 else
571 {
572 return program->second;
573 }
574}
575
576Texture *Context::getTexture(unsigned int handle)
577{
578 TextureMap::iterator texture = mTextureMap.find(handle);
579
580 if (texture == mTextureMap.end())
581 {
582 return NULL;
583 }
584 else
585 {
586 return texture->second;
587 }
588}
589
590Framebuffer *Context::getFramebuffer(unsigned int handle)
591{
592 FramebufferMap::iterator framebuffer = mFramebufferMap.find(handle);
593
594 if (framebuffer == mFramebufferMap.end())
595 {
596 return NULL;
597 }
598 else
599 {
600 return framebuffer->second;
601 }
602}
603
604Renderbuffer *Context::getRenderbuffer(unsigned int handle)
605{
606 RenderbufferMap::iterator renderbuffer = mRenderbufferMap.find(handle);
607
608 if (renderbuffer == mRenderbufferMap.end())
609 {
610 return NULL;
611 }
612 else
613 {
614 return renderbuffer->second;
615 }
616}
617
618Colorbuffer *Context::getColorbuffer(GLuint handle)
619{
620 if (handle != 0)
621 {
622 Renderbuffer *renderbuffer = getRenderbuffer(handle);
623
624 if(renderbuffer && renderbuffer->isColorbuffer())
625 {
626 return static_cast<Colorbuffer*>(renderbuffer);
627 }
628 }
629 else // Special case: 0 refers to different initial render targets based on the attachment type
630 {
631 return mColorbufferZero;
632 }
633
634 return NULL;
635}
636
637Depthbuffer *Context::getDepthbuffer(GLuint handle)
638{
639 if (handle != 0)
640 {
641 Renderbuffer *renderbuffer = getRenderbuffer(handle);
642
643 if(renderbuffer && renderbuffer->isDepthbuffer())
644 {
645 return static_cast<Depthbuffer*>(renderbuffer);
646 }
647 }
648 else // Special case: 0 refers to different initial render targets based on the attachment type
649 {
650 return mDepthbufferZero;
651 }
652
653 return NULL;
654}
655
656Stencilbuffer *Context::getStencilbuffer(GLuint handle)
657{
658 if (handle != 0)
659 {
660 Renderbuffer *renderbuffer = getRenderbuffer(handle);
661
662 if(renderbuffer && renderbuffer->isStencilbuffer())
663 {
664 return static_cast<Stencilbuffer*>(renderbuffer);
665 }
666 }
667 else
668 {
669 return mStencilbufferZero;
670 }
671
672 return NULL;
673}
674
675Buffer *Context::getArrayBuffer()
676{
677 return getBuffer(arrayBuffer);
678}
679
680Buffer *Context::getElementArrayBuffer()
681{
682 return getBuffer(elementArrayBuffer);
683}
684
685Program *Context::getCurrentProgram()
686{
687 return getProgram(currentProgram);
688}
689
690Texture2D *Context::getTexture2D()
691{
692 if (texture2D == 0) // Special case: 0 refers to different initial textures based on the target
693 {
694 return mTexture2DZero;
695 }
696
697 return (Texture2D*)getTexture(texture2D);
698}
699
700TextureCubeMap *Context::getTextureCubeMap()
701{
702 if (textureCubeMap == 0) // Special case: 0 refers to different initial textures based on the target
703 {
704 return mTextureCubeMapZero;
705 }
706
707 return (TextureCubeMap*)getTexture(textureCubeMap);
708}
709
710Texture *Context::getSamplerTexture(unsigned int sampler)
711{
712 return getTexture(samplerTexture[sampler]);
713}
714
715Framebuffer *Context::getFramebuffer()
716{
717 return getFramebuffer(framebuffer);
718}
719
720// Applies the render target surface, depth stencil surface, viewport rectangle and
721// scissor rectangle to the Direct3D 9 device
722bool Context::applyRenderTarget(bool ignoreViewport)
723{
724 IDirect3DDevice9 *device = getDevice();
725 Framebuffer *framebufferObject = getFramebuffer();
726
727 if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE)
728 {
729 return false;
730 }
731
732 IDirect3DSurface9 *renderTarget = framebufferObject->getRenderTarget();
733 IDirect3DSurface9 *depthStencil = framebufferObject->getDepthStencil();
734
735 device->SetRenderTarget(0, renderTarget);
736 device->SetDepthStencilSurface(depthStencil);
737
738 D3DVIEWPORT9 viewport;
739 D3DSURFACE_DESC desc;
740 renderTarget->GetDesc(&desc);
741
742 if (ignoreViewport)
743 {
744 viewport.X = 0;
745 viewport.Y = 0;
746 viewport.Width = desc.Width;
747 viewport.Height = desc.Height;
748 viewport.MinZ = 0.0f;
749 viewport.MaxZ = 1.0f;
750 }
751 else
752 {
753 viewport.X = max(viewportX, 0);
754 viewport.Y = max(viewportY, 0);
755 viewport.Width = min(viewportWidth, (int)desc.Width - (int)viewport.X);
756 viewport.Height = min(viewportHeight, (int)desc.Height - (int)viewport.Y);
757 viewport.MinZ = clamp01(zNear);
758 viewport.MaxZ = clamp01(zFar);
759 }
760
761 device->SetViewport(&viewport);
762
763 if (scissorTest)
764 {
765 RECT rect = {scissorX,
766 scissorY,
767 scissorX + scissorWidth,
768 scissorY + scissorHeight};
769
770 device->SetScissorRect(&rect);
771 device->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
772 }
773 else
774 {
775 device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
776 }
777
778 if (currentProgram)
779 {
780 D3DSURFACE_DESC description;
781 renderTarget->GetDesc(&description);
782 Program *programObject = getCurrentProgram();
783
784 GLuint halfPixelSize = programObject->getUniformLocation("gl_HalfPixelSize");
785 GLfloat xy[2] = {1.0f / description.Width, 1.0f / description.Height};
786 programObject->setUniform2fv(halfPixelSize, 1, (GLfloat*)&xy);
787 }
788
789 return true;
790}
791
792// Applies the fixed-function state (culling, depth test, alpha blending, stenciling, etc) to the Direct3D 9 device
793void Context::applyState()
794{
795 IDirect3DDevice9 *device = getDevice();
796
797 if (cullFace)
798 {
799 device->SetRenderState(D3DRS_CULLMODE, es2dx::ConvertCullMode(cullMode, frontFace));
800 }
801 else
802 {
803 device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
804 }
805
806 if (depthTest)
807 {
808 device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
809 device->SetRenderState(D3DRS_ZFUNC, es2dx::ConvertComparison(depthFunc));
810 }
811 else
812 {
813 device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
814 }
815
816 if (blend)
817 {
818 device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
819
820 if (sourceBlendRGB != GL_CONSTANT_ALPHA && sourceBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA &&
821 destBlendRGB != GL_CONSTANT_ALPHA && destBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA)
822 {
823 device->SetRenderState(D3DRS_BLENDFACTOR, es2dx::ConvertColor(blendColor));
824 }
825 else
826 {
827 device->SetRenderState(D3DRS_BLENDFACTOR, D3DCOLOR_RGBA(unorm<8>(blendColor.alpha),
828 unorm<8>(blendColor.alpha),
829 unorm<8>(blendColor.alpha),
830 unorm<8>(blendColor.alpha)));
831 }
832
833 device->SetRenderState(D3DRS_SRCBLEND, es2dx::ConvertBlendFunc(sourceBlendRGB));
834 device->SetRenderState(D3DRS_DESTBLEND, es2dx::ConvertBlendFunc(destBlendRGB));
835 device->SetRenderState(D3DRS_BLENDOP, es2dx::ConvertBlendOp(blendEquationRGB));
836
837 if (sourceBlendRGB != sourceBlendAlpha || destBlendRGB != destBlendAlpha || blendEquationRGB != blendEquationAlpha)
838 {
839 device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
840
841 device->SetRenderState(D3DRS_SRCBLENDALPHA, es2dx::ConvertBlendFunc(sourceBlendAlpha));
842 device->SetRenderState(D3DRS_DESTBLENDALPHA, es2dx::ConvertBlendFunc(destBlendAlpha));
843 device->SetRenderState(D3DRS_BLENDOPALPHA, es2dx::ConvertBlendOp(blendEquationAlpha));
844
845 }
846 else
847 {
848 device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
849 }
850 }
851 else
852 {
853 device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
854 }
855
856 if (stencilTest)
857 {
858 device->SetRenderState(D3DRS_STENCILENABLE, TRUE);
859 device->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE);
860
861 // FIXME: Unsupported by D3D9
862 const D3DRENDERSTATETYPE D3DRS_CCW_STENCILREF = D3DRS_STENCILREF;
863 const D3DRENDERSTATETYPE D3DRS_CCW_STENCILMASK = D3DRS_STENCILMASK;
864 const D3DRENDERSTATETYPE D3DRS_CCW_STENCILWRITEMASK = D3DRS_STENCILWRITEMASK;
865 ASSERT(stencilRef == stencilBackRef);
866 ASSERT(stencilMask == stencilBackMask);
867 ASSERT(stencilWritemask == stencilBackWritemask);
868
869 device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, stencilWritemask);
870 device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, es2dx::ConvertComparison(stencilFunc));
871
872 device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, stencilRef); // FIXME: Clamp to range
873 device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, stencilMask);
874
875 device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, es2dx::ConvertStencilOp(stencilFail));
876 device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, es2dx::ConvertStencilOp(stencilPassDepthFail));
877 device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, es2dx::ConvertStencilOp(stencilPassDepthPass));
878
879 device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, stencilBackWritemask);
880 device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, es2dx::ConvertComparison(stencilBackFunc));
881
882 device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, stencilBackRef); // FIXME: Clamp to range
883 device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, stencilBackMask);
884
885 device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, es2dx::ConvertStencilOp(stencilBackFail));
886 device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, es2dx::ConvertStencilOp(stencilBackPassDepthFail));
887 device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, es2dx::ConvertStencilOp(stencilBackPassDepthPass));
888 }
889 else
890 {
891 device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
892 }
893
894 device->SetRenderState(D3DRS_COLORWRITEENABLE, es2dx::ConvertColorMask(colorMaskRed, colorMaskGreen, colorMaskBlue, colorMaskAlpha));
895 device->SetRenderState(D3DRS_ZWRITEENABLE, depthMask ? TRUE : FALSE);
896
897 if (polygonOffsetFill)
898 {
899 UNIMPLEMENTED(); // FIXME
900 }
901
902 if (sampleAlphaToCoverage)
903 {
904 UNIMPLEMENTED(); // FIXME
905 }
906
907 if (sampleCoverage)
908 {
909 UNIMPLEMENTED(); // FIXME: Ignore when SAMPLE_BUFFERS is not one
910 }
911
912 device->SetRenderState(D3DRS_DITHERENABLE, dither ? TRUE : FALSE);
913}
914
915// Applies the vertex attribute and array bindings to the Direct3D 9 device
916void Context::applyVertexBuffer(int count)
917{
918 IDirect3DDevice9 *device = getDevice();
919 Program *programObject = getCurrentProgram();
920 IDirect3DVertexShader9 *vertexShader = programObject->getVertexShader();
921
922 D3DVERTEXELEMENT9 vertexElements[MAX_VERTEX_ATTRIBS + 1];
923 D3DVERTEXELEMENT9 *currentElement = &vertexElements[0];
924
925 for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
926 {
927 if (vertexAttribute[attributeIndex].enabled && programObject->isActiveAttribute(attributeIndex))
928 {
929 GLuint boundBuffer = vertexAttribute[attributeIndex].boundBuffer;
930 UINT stride = vertexAttribute[attributeIndex].stride;
931 GLint size = vertexAttribute[attributeIndex].size;
932 GLenum type = vertexAttribute[attributeIndex].type;
933
934 if (stride == 0)
935 {
936 switch (type)
937 {
938 case GL_BYTE: stride = size * sizeof(GLbyte); break;
939 case GL_UNSIGNED_BYTE: stride = size * sizeof(GLubyte); break;
940 case GL_SHORT: stride = size * sizeof(GLshort); break;
941 case GL_UNSIGNED_SHORT: stride = size * sizeof(GLushort); break;
942 case GL_FIXED: stride = size * sizeof(GLfixed); break;
943 case GL_FLOAT: stride = size * sizeof(GLfloat); break;
944 default: UNREACHABLE();
945 }
946 }
947
948 currentElement->Stream = attributeIndex;
949
950 if (boundBuffer)
951 {
952 currentElement->Offset = (unsigned short)vertexAttribute[attributeIndex].pointer;
953 }
954 else
955 {
956 currentElement->Offset = 0;
957 }
958
959 switch (type)
960 {
961 case GL_BYTE:
962 if (vertexAttribute[attributeIndex].normalized)
963 {
964 UNIMPLEMENTED(); // FIXME
965 }
966 else
967 {
968 UNIMPLEMENTED(); // FIXME
969 }
970 break;
971 case GL_UNSIGNED_BYTE:
972 if (vertexAttribute[attributeIndex].normalized)
973 {
974 switch (size)
975 {
976 case 1: UNIMPLEMENTED(); // FIXME
977 case 2: UNIMPLEMENTED(); // FIXME
978 case 3: UNIMPLEMENTED(); // FIXME
979 case 4: currentElement->Type = D3DDECLTYPE_UBYTE4N; break;
980 default: UNREACHABLE();
981 }
982 }
983 else
984 {
985 UNIMPLEMENTED(); // FIXME
986 }
987 break;
988 case GL_SHORT:
989 if (vertexAttribute[attributeIndex].normalized)
990 {
991 UNIMPLEMENTED(); // FIXME
992 }
993 else
994 {
995 UNIMPLEMENTED(); // FIXME
996 }
997 break;
998 case GL_UNSIGNED_SHORT:
999 if (vertexAttribute[attributeIndex].normalized)
1000 {
1001 UNIMPLEMENTED(); // FIXME
1002 }
1003 else
1004 {
1005 UNIMPLEMENTED(); // FIXME
1006 }
1007 break;
1008 case GL_FIXED:
1009 UNIMPLEMENTED(); // FIXME
1010 break;
1011 case GL_FLOAT:
1012 switch (size)
1013 {
1014 case 1: currentElement->Type = D3DDECLTYPE_FLOAT1; break;
1015 case 2: currentElement->Type = D3DDECLTYPE_FLOAT2; break;
1016 case 3: currentElement->Type = D3DDECLTYPE_FLOAT3; break;
1017 case 4: currentElement->Type = D3DDECLTYPE_FLOAT4; break;
1018 default: UNREACHABLE();
1019 }
1020 break;
1021 default: UNREACHABLE();
1022 }
1023
1024 currentElement->Method = D3DDECLMETHOD_DEFAULT;
1025 currentElement->Usage = D3DDECLUSAGE_TEXCOORD;
1026 currentElement->UsageIndex = programObject->getInputMapping(attributeIndex);
1027
1028 currentElement++;
1029
1030 if (boundBuffer)
1031 {
1032 Buffer *buffer = getBuffer(boundBuffer);
1033 IDirect3DVertexBuffer9 *streamData = buffer->getVertexBuffer();
1034 device->SetStreamSource(attributeIndex, streamData, 0, stride);
1035 }
1036 else if (vertexAttribute[attributeIndex].pointer)
1037 {
1038 IDirect3DVertexBuffer9 *vertexBuffer = NULL;
1039 void *data;
1040
1041 HRESULT result = device->CreateVertexBuffer(stride * count, 0, 0, D3DPOOL_MANAGED, &vertexBuffer, NULL);
1042
1043 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
1044 {
1045 return error(GL_OUT_OF_MEMORY);
1046 }
1047
1048 ASSERT(SUCCEEDED(result));
1049
1050 vertexBuffer->Lock(0, 0, &data, 0);
1051 memcpy(data, vertexAttribute[attributeIndex].pointer, stride *count);
1052 vertexBuffer->Unlock();
1053
1054 device->SetStreamSource(attributeIndex, vertexBuffer, 0, stride);
1055 vertexBuffer->Release();
1056 }
1057 else UNIMPLEMENTED(); // FIXME
1058 }
1059 else
1060 {
1061 device->SetStreamSource(attributeIndex, NULL, 0, 0);
1062 }
1063 }
1064
1065 D3DVERTEXELEMENT9 end = D3DDECL_END();
1066 *currentElement = end;
1067
1068 IDirect3DVertexDeclaration9 *vertexDeclaration = NULL;
1069 HRESULT result = device->CreateVertexDeclaration(vertexElements, &vertexDeclaration);
1070
1071 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
1072 {
1073 return error(GL_OUT_OF_MEMORY);
1074 }
1075
1076 ASSERT(SUCCEEDED(result));
1077
1078 if (vertexDeclaration)
1079 {
1080 device->SetVertexDeclaration(vertexDeclaration);
1081 vertexDeclaration->Release(); // Will only effectively be deleted when no longer in use
1082 }
1083}
1084
1085// Applies the indices and element array bindings to the Direct3D 9 device
1086void Context::applyIndexBuffer(const void *indices, int length)
1087{
1088 IDirect3DDevice9 *device = getDevice();
1089
1090 if (elementArrayBuffer)
1091 {
1092 Buffer *buffer = getBuffer(elementArrayBuffer);
1093 IDirect3DIndexBuffer9 *indexBuffer = buffer->getIndexBuffer();
1094
1095 device->SetIndices(indexBuffer);
1096 startIndex = (unsigned int)(size_t)indices / 2; // FIXME: Assumes even value and 16-bit indices
1097 }
1098 else if (indices)
1099 {
1100 IDirect3DIndexBuffer9 *indexBuffer = NULL;
1101 void *data;
1102
1103 HRESULT result = device->CreateIndexBuffer(length, 0, D3DFMT_INDEX16, D3DPOOL_MANAGED, &indexBuffer, NULL);
1104
1105 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
1106 {
1107 return error(GL_OUT_OF_MEMORY);
1108 }
1109
1110 ASSERT(SUCCEEDED(result));
1111
1112 if (indexBuffer)
1113 {
1114 indexBuffer->Lock(0, length, &data, 0);
1115 memcpy(data, indices, length);
1116 indexBuffer->Unlock();
1117
1118 device->SetIndices(indexBuffer);
1119 indexBuffer->Release(); // Will only effectively be deleted when no longer in use
1120 }
1121
1122 startIndex = 0;
1123 }
1124 else UNREACHABLE();
1125}
1126
1127// Applies the shaders and shader constants to the Direct3D 9 device
1128void Context::applyShaders()
1129{
1130 IDirect3DDevice9 *device = getDevice();
1131 Program *programObject = getCurrentProgram();
1132 IDirect3DVertexShader9 *vertexShader = programObject->getVertexShader();
1133 IDirect3DPixelShader9 *pixelShader = programObject->getPixelShader();
1134
1135 device->SetVertexShader(vertexShader);
1136 device->SetPixelShader(pixelShader);
1137
1138 programObject->applyUniforms();
1139}
1140
1141// Applies the textures and sampler states to the Direct3D 9 device
1142void Context::applyTextures()
1143{
1144 IDirect3DDevice9 *device = getDevice();
1145 Program *programObject = getCurrentProgram();
1146
1147 for (int sampler = 0; sampler < MAX_TEXTURE_IMAGE_UNITS; sampler++)
1148 {
1149 unsigned int textureUnit = programObject->getSamplerMapping(sampler);
1150 Texture *texture = getSamplerTexture(textureUnit);
1151
1152 if (texture && texture->isComplete())
1153 {
1154 GLenum wrapS = texture->getWrapS();
1155 GLenum wrapT = texture->getWrapT();
1156 GLenum minFilter = texture->getMinFilter();
1157 GLenum magFilter = texture->getMagFilter();
1158
1159 device->SetSamplerState(sampler, D3DSAMP_ADDRESSU, es2dx::ConvertTextureWrap(wrapS));
1160 device->SetSamplerState(sampler, D3DSAMP_ADDRESSV, es2dx::ConvertTextureWrap(wrapT));
1161
1162 device->SetSamplerState(sampler, D3DSAMP_MAGFILTER, es2dx::ConvertMagFilter(magFilter));
1163 D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter;
1164 es2dx::ConvertMinFilter(minFilter, &d3dMinFilter, &d3dMipFilter);
1165 device->SetSamplerState(sampler, D3DSAMP_MINFILTER, d3dMinFilter);
1166 device->SetSamplerState(sampler, D3DSAMP_MIPFILTER, d3dMipFilter);
1167
1168 device->SetTexture(sampler, texture->getTexture());
1169 }
1170 }
1171}
1172
1173void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels)
1174{
1175 Framebuffer *framebuffer = getFramebuffer();
1176 IDirect3DSurface9 *renderTarget = framebuffer->getRenderTarget();
1177 IDirect3DDevice9 *device = getDevice();
1178
1179 D3DSURFACE_DESC desc;
1180 renderTarget->GetDesc(&desc);
1181
1182 IDirect3DSurface9 *systemSurface;
1183 HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &systemSurface, NULL);
1184
1185 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
1186 {
1187 return error(GL_OUT_OF_MEMORY);
1188 }
1189
1190 ASSERT(SUCCEEDED(result));
1191
1192 if (desc.MultiSampleType != D3DMULTISAMPLE_NONE)
1193 {
1194 UNIMPLEMENTED(); // FIXME: Requires resolve using StretchRect into non-multisampled render target
1195 }
1196
1197 result = device->GetRenderTargetData(renderTarget, systemSurface);
1198
1199 if (result == D3DERR_DRIVERINTERNALERROR)
1200 {
1201 systemSurface->Release();
1202
1203 return error(GL_OUT_OF_MEMORY);
1204 }
1205
1206 if (FAILED(result))
1207 {
1208 UNREACHABLE();
1209 systemSurface->Release();
1210
1211 return; // No sensible error to generate
1212 }
1213
1214 D3DLOCKED_RECT lock;
1215 RECT rect = {max(x, 0),
1216 max(y, 0),
1217 min(x + width, (int)desc.Width),
1218 min(y + height, (int)desc.Height)};
1219
1220 result = systemSurface->LockRect(&lock, &rect, D3DLOCK_READONLY);
1221
1222 if (FAILED(result))
1223 {
1224 UNREACHABLE();
1225 systemSurface->Release();
1226
1227 return; // No sensible error to generate
1228 }
1229
1230 unsigned char *source = (unsigned char*)lock.pBits;
1231 unsigned char *dest = (unsigned char*)pixels;
1232
1233 for (int j = 0; j < rect.bottom - rect.top; j++)
1234 {
1235 for (int i = 0; i < rect.right - rect.left; i++)
1236 {
1237 float r;
1238 float g;
1239 float b;
1240 float a;
1241
1242 switch (desc.Format)
1243 {
1244 case D3DFMT_R5G6B5:
1245 {
1246 unsigned short rgb = *(unsigned short*)(source + 2 * i + j * lock.Pitch);
1247
1248 a = 1.0f;
1249 b = (rgb & 0x001F) * (1.0f / 0x001F);
1250 g = (rgb & 0x07E0) * (1.0f / 0x07E0);
1251 r = (rgb & 0xF800) * (1.0f / 0xF800);
1252 }
1253 break;
1254 case D3DFMT_X1R5G5B5:
1255 {
1256 unsigned short xrgb = *(unsigned short*)(source + 2 * i + j * lock.Pitch);
1257
1258 a = 1.0f;
1259 b = (xrgb & 0x001F) * (1.0f / 0x001F);
1260 g = (xrgb & 0x03E0) * (1.0f / 0x03E0);
1261 r = (xrgb & 0x7C00) * (1.0f / 0x7C00);
1262 }
1263 break;
1264 case D3DFMT_A1R5G5B5:
1265 {
1266 unsigned short argb = *(unsigned short*)(source + 2 * i + j * lock.Pitch);
1267
1268 a = (argb & 0x8000) ? 1.0f : 0.0f;
1269 b = (argb & 0x001F) * (1.0f / 0x001F);
1270 g = (argb & 0x03E0) * (1.0f / 0x03E0);
1271 r = (argb & 0x7C00) * (1.0f / 0x7C00);
1272 }
1273 break;
1274 case D3DFMT_A8R8G8B8:
1275 {
1276 unsigned int argb = *(unsigned int*)(source + 4 * i + j * lock.Pitch);
1277
1278 a = (argb & 0xFF000000) * (1.0f / 0xFF000000);
1279 b = (argb & 0x000000FF) * (1.0f / 0x000000FF);
1280 g = (argb & 0x0000FF00) * (1.0f / 0x0000FF00);
1281 r = (argb & 0x00FF0000) * (1.0f / 0x00FF0000);
1282 }
1283 break;
1284 case D3DFMT_X8R8G8B8:
1285 {
1286 unsigned int xrgb = *(unsigned int*)(source + 4 * i + j * lock.Pitch);
1287
1288 a = 1.0f;
1289 b = (xrgb & 0x000000FF) * (1.0f / 0x000000FF);
1290 g = (xrgb & 0x0000FF00) * (1.0f / 0x0000FF00);
1291 r = (xrgb & 0x00FF0000) * (1.0f / 0x00FF0000);
1292 }
1293 break;
1294 case D3DFMT_A2R10G10B10:
1295 {
1296 unsigned int argb = *(unsigned int*)(source + 4 * i + j * lock.Pitch);
1297
1298 a = (argb & 0xC0000000) * (1.0f / 0xC0000000);
1299 b = (argb & 0x000003FF) * (1.0f / 0x000003FF);
1300 g = (argb & 0x000FFC00) * (1.0f / 0x000FFC00);
1301 r = (argb & 0x3FF00000) * (1.0f / 0x3FF00000);
1302 }
1303 break;
1304 default:
1305 UNIMPLEMENTED(); // FIXME
1306 UNREACHABLE();
1307 }
1308
1309 switch (format)
1310 {
1311 case GL_RGBA:
1312 switch (type)
1313 {
1314 case GL_UNSIGNED_BYTE:
1315 dest[4 * (i + j * width) + 0] = (unsigned char)(255 * r + 0.5f);
1316 dest[4 * (i + j * width) + 1] = (unsigned char)(255 * g + 0.5f);
1317 dest[4 * (i + j * width) + 2] = (unsigned char)(255 * b + 0.5f);
1318 dest[4 * (i + j * width) + 3] = (unsigned char)(255 * a + 0.5f);
1319 break;
1320 default: UNREACHABLE();
1321 }
1322 break;
1323 case IMPLEMENTATION_COLOR_READ_FORMAT:
1324 switch (type)
1325 {
1326 case IMPLEMENTATION_COLOR_READ_TYPE:
1327 break;
1328 default: UNREACHABLE();
1329 }
1330 break;
1331 default: UNREACHABLE();
1332 }
1333 }
1334 }
1335
1336 systemSurface->UnlockRect();
1337
1338 systemSurface->Release();
1339}
1340
1341void Context::clear(GLbitfield mask)
1342{
1343 IDirect3DDevice9 *device = getDevice();
1344 DWORD flags = 0;
1345
1346 if (mask & GL_COLOR_BUFFER_BIT)
1347 {
1348 mask &= ~GL_COLOR_BUFFER_BIT;
1349 flags |= D3DCLEAR_TARGET;
1350 }
1351
1352 if (mask & GL_DEPTH_BUFFER_BIT)
1353 {
1354 mask &= ~GL_DEPTH_BUFFER_BIT;
1355 if (depthMask)
1356 {
1357 flags |= D3DCLEAR_ZBUFFER;
1358 }
1359 }
1360
1361 Framebuffer *framebufferObject = getFramebuffer();
1362 IDirect3DSurface9 *depthStencil = framebufferObject->getDepthStencil();
1363
1364 GLuint stencilUnmasked = 0x0;
1365
1366 if ((mask & GL_STENCIL_BUFFER_BIT) && depthStencil)
1367 {
1368 D3DSURFACE_DESC desc;
1369 depthStencil->GetDesc(&desc);
1370
1371 mask &= ~GL_STENCIL_BUFFER_BIT;
1372 unsigned int stencilSize = es2dx::GetStencilSize(desc.Format);
1373 stencilUnmasked = (0x1 << stencilSize) - 1;
1374
1375 if (stencilUnmasked != 0x0)
1376 {
1377 flags |= D3DCLEAR_STENCIL;
1378 }
1379 }
1380
1381 if (mask != 0)
1382 {
1383 return error(GL_INVALID_VALUE);
1384 }
1385
1386 applyRenderTarget(true); // Clips the clear to the scissor rectangle but not the viewport
1387
1388 D3DCOLOR color = D3DCOLOR_ARGB(unorm<8>(colorClearValue.alpha), unorm<8>(colorClearValue.red), unorm<8>(colorClearValue.green), unorm<8>(colorClearValue.blue));
1389 float depth = clamp01(depthClearValue);
1390 int stencil = stencilClearValue & 0x000000FF;
1391
1392 IDirect3DSurface9 *renderTarget = framebufferObject->getRenderTarget();
1393
1394 D3DSURFACE_DESC desc;
1395 renderTarget->GetDesc(&desc);
1396
1397 bool alphaUnmasked = (es2dx::GetAlphaSize(desc.Format) == 0) || colorMaskAlpha;
1398
1399 const bool needMaskedStencilClear = (flags & D3DCLEAR_STENCIL) &&
1400 (stencilWritemask & stencilUnmasked) != stencilUnmasked;
1401 const bool needMaskedColorClear = (flags & D3DCLEAR_TARGET) &&
1402 !(colorMaskRed && colorMaskGreen &&
1403 colorMaskBlue && alphaUnmasked);
1404
1405 if (needMaskedColorClear || needMaskedStencilClear)
1406 {
1407 device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
1408 device->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
1409 device->SetRenderState(D3DRS_ZENABLE, FALSE);
1410 device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
1411 device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
1412 device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
1413 device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
1414 device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
1415
1416 if (flags & D3DCLEAR_TARGET)
1417 {
1418 device->SetRenderState(D3DRS_COLORWRITEENABLE, (colorMaskRed ? D3DCOLORWRITEENABLE_RED : 0) |
1419 (colorMaskGreen ? D3DCOLORWRITEENABLE_GREEN : 0) |
1420 (colorMaskBlue ? D3DCOLORWRITEENABLE_BLUE : 0) |
1421 (colorMaskAlpha ? D3DCOLORWRITEENABLE_ALPHA : 0));
1422 }
1423 else
1424 {
1425 device->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
1426 }
1427
1428 if (stencilUnmasked != 0x0 && (flags & D3DCLEAR_STENCIL))
1429 {
1430 device->SetRenderState(D3DRS_STENCILENABLE, TRUE);
1431 device->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
1432 device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);
1433 device->SetRenderState(D3DRS_STENCILREF, stencil);
1434 device->SetRenderState(D3DRS_STENCILWRITEMASK, stencilWritemask);
1435 device->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE);
1436 device->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_REPLACE);
1437 device->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE);
1438 }
1439 else
1440 {
1441 device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
1442 }
1443
1444 device->SetPixelShader(NULL);
1445 device->SetVertexShader(NULL);
1446 device->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
1447
1448 struct Vertex
1449 {
1450 float x, y, z, w;
1451 D3DCOLOR diffuse;
1452 };
1453
1454 Vertex quad[4];
1455 quad[0].x = 0.0f;
1456 quad[0].y = (float)desc.Height;
1457 quad[0].z = 0.0f;
1458 quad[0].w = 1.0f;
1459 quad[0].diffuse = color;
1460
1461 quad[1].x = (float)desc.Width;
1462 quad[1].y = (float)desc.Height;
1463 quad[1].z = 0.0f;
1464 quad[1].w = 1.0f;
1465 quad[1].diffuse = color;
1466
1467 quad[2].x = 0.0f;
1468 quad[2].y = 0.0f;
1469 quad[2].z = 0.0f;
1470 quad[2].w = 1.0f;
1471 quad[2].diffuse = color;
1472
1473 quad[3].x = (float)desc.Width;
1474 quad[3].y = 0.0f;
1475 quad[3].z = 0.0f;
1476 quad[3].w = 1.0f;
1477 quad[3].diffuse = color;
1478
1479 device->BeginScene();
1480 device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(Vertex));
1481 device->EndScene();
1482
1483 if (flags & D3DCLEAR_ZBUFFER)
1484 {
1485 device->SetRenderState(D3DRS_ZENABLE, TRUE);
1486 device->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
1487 device->Clear(0, NULL, D3DCLEAR_ZBUFFER, color, depth, stencil);
1488 }
1489 }
1490 else
1491 {
1492 device->Clear(0, NULL, flags, color, depth, stencil);
1493 }
1494}
1495
1496void Context::drawArrays(GLenum mode, GLint first, GLsizei count)
1497{
1498 if (!currentProgram)
1499 {
1500 return error(GL_INVALID_OPERATION);
1501 }
1502
1503 IDirect3DDevice9 *device = getDevice();
1504 D3DPRIMITIVETYPE primitiveType;
1505 int primitiveCount;
1506
1507 if(!es2dx::ConvertPrimitiveType(mode, count, &primitiveType, &primitiveCount))
1508 return error(GL_INVALID_ENUM);
1509
1510 if (primitiveCount <= 0)
1511 {
1512 return;
1513 }
1514
1515 if (!applyRenderTarget(false))
1516 {
1517 return error(GL_INVALID_FRAMEBUFFER_OPERATION);
1518 }
1519
1520 applyState();
1521 applyVertexBuffer(count);
1522 applyShaders();
1523 applyTextures();
1524
1525 device->BeginScene();
1526 device->DrawPrimitive(primitiveType, first, primitiveCount);
1527 device->EndScene();
1528}
1529
1530void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const void* indices)
1531{
1532 if (!currentProgram)
1533 {
1534 return error(GL_INVALID_OPERATION);
1535 }
1536
1537 if (!indices && !elementArrayBuffer)
1538 {
1539 return error(GL_INVALID_OPERATION);
1540 }
1541
1542 IDirect3DDevice9 *device = getDevice();
1543 D3DPRIMITIVETYPE primitiveType;
1544 int primitiveCount;
1545
1546 if(!es2dx::ConvertPrimitiveType(mode, count, &primitiveType, &primitiveCount))
1547 return error(GL_INVALID_ENUM);
1548
1549 if (primitiveCount <= 0)
1550 {
1551 return;
1552 }
1553
1554 if (!applyRenderTarget(false))
1555 {
1556 return error(GL_INVALID_FRAMEBUFFER_OPERATION);
1557 }
1558
1559 applyState();
1560 applyVertexBuffer(count);
1561 applyIndexBuffer(indices, count * sizeof(unsigned short));
1562 applyShaders();
1563 applyTextures();
1564
1565 device->BeginScene();
1566 device->DrawIndexedPrimitive(primitiveType, 0, 0, count, startIndex, primitiveCount);
1567 device->EndScene();
1568}
1569
1570void Context::finish()
1571{
1572 IDirect3DDevice9 *device = getDevice();
1573 IDirect3DQuery9 *occlusionQuery = NULL;
1574
1575 HRESULT result = device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery);
1576
1577 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
1578 {
1579 return error(GL_OUT_OF_MEMORY);
1580 }
1581
1582 ASSERT(SUCCEEDED(result));
1583
1584 if (occlusionQuery)
1585 {
1586 occlusionQuery->Issue(D3DISSUE_BEGIN);
1587
1588 // Render something outside the render target
1589 device->SetPixelShader(NULL);
1590 device->SetVertexShader(NULL);
1591 device->SetFVF(D3DFVF_XYZRHW);
1592 float data[4] = {-1.0f, -1.0f, -1.0f, 1.0f};
1593 device->BeginScene();
1594 device->DrawPrimitiveUP(D3DPT_POINTLIST, 1, data, sizeof(data));
1595 device->EndScene();
1596
1597 occlusionQuery->Issue(D3DISSUE_END);
1598
1599 while (occlusionQuery->GetData(NULL, 0, D3DGETDATA_FLUSH) == S_FALSE)
1600 {
1601 // Keep polling, but allow other threads to do something useful first
1602 Sleep(0);
1603 }
1604
1605 occlusionQuery->Release();
1606 }
1607}
1608
1609void Context::flush()
1610{
1611 IDirect3DDevice9 *device = getDevice();
1612 IDirect3DQuery9 *eventQuery = NULL;
1613
1614 HRESULT result = device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery);
1615
1616 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
1617 {
1618 return error(GL_OUT_OF_MEMORY);
1619 }
1620
1621 ASSERT(SUCCEEDED(result));
1622
1623 if (eventQuery)
1624 {
1625 eventQuery->Issue(D3DISSUE_END);
1626
1627 while (eventQuery->GetData(NULL, 0, D3DGETDATA_FLUSH) == S_FALSE)
1628 {
1629 // Keep polling, but allow other threads to do something useful first
1630 Sleep(0);
1631 }
1632
1633 eventQuery->Release();
1634 }
1635}
1636
1637void Context::recordInvalidEnum()
1638{
1639 mInvalidEnum = true;
1640}
1641
1642void Context::recordInvalidValue()
1643{
1644 mInvalidValue = true;
1645}
1646
1647void Context::recordInvalidOperation()
1648{
1649 mInvalidOperation = true;
1650}
1651
1652void Context::recordOutOfMemory()
1653{
1654 mOutOfMemory = true;
1655}
1656
1657void Context::recordInvalidFramebufferOperation()
1658{
1659 mInvalidFramebufferOperation = true;
1660}
1661
1662// Get one of the recorded errors and clear its flag, if any.
1663// [OpenGL ES 2.0.24] section 2.5 page 13.
1664GLenum Context::getError()
1665{
1666 if (mInvalidEnum)
1667 {
1668 mInvalidEnum = false;
1669
1670 return GL_INVALID_ENUM;
1671 }
1672
1673 if (mInvalidValue)
1674 {
1675 mInvalidValue = false;
1676
1677 return GL_INVALID_VALUE;
1678 }
1679
1680 if (mInvalidOperation)
1681 {
1682 mInvalidOperation = false;
1683
1684 return GL_INVALID_OPERATION;
1685 }
1686
1687 if (mOutOfMemory)
1688 {
1689 mOutOfMemory = false;
1690
1691 return GL_OUT_OF_MEMORY;
1692 }
1693
1694 if (mInvalidFramebufferOperation)
1695 {
1696 mInvalidFramebufferOperation = false;
1697
1698 return GL_INVALID_FRAMEBUFFER_OPERATION;
1699 }
1700
1701 return GL_NO_ERROR;
1702}
1703
1704void Context::detachBuffer(GLuint buffer)
1705{
1706 // [OpenGL ES 2.0.24] section 2.9 page 22:
1707 // If a buffer object is deleted while it is bound, all bindings to that object in the current context
1708 // (i.e. in the thread that called Delete-Buffers) are reset to zero.
1709
1710 if (arrayBuffer == buffer)
1711 {
1712 arrayBuffer = 0;
1713 }
1714
1715 if (elementArrayBuffer == buffer)
1716 {
1717 elementArrayBuffer = 0;
1718 }
1719
1720 for (int attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
1721 {
1722 if (vertexAttribute[attribute].boundBuffer == buffer)
1723 {
1724 vertexAttribute[attribute].boundBuffer = 0;
1725 }
1726 }
1727}
1728
1729void Context::detachTexture(GLuint texture)
1730{
1731 // [OpenGL ES 2.0.24] section 3.8 page 84:
1732 // If a texture object is deleted, it is as if all texture units which are bound to that texture object are
1733 // rebound to texture object zero
1734
1735 for (int sampler = 0; sampler < MAX_TEXTURE_IMAGE_UNITS; sampler++)
1736 {
1737 if (samplerTexture[sampler] == texture)
1738 {
1739 samplerTexture[sampler] = 0;
1740 }
1741 }
1742
1743 // [OpenGL ES 2.0.24] section 4.4 page 112:
1744 // If a texture object is deleted while its image is attached to the currently bound framebuffer, then it is
1745 // as if FramebufferTexture2D had been called, with a texture of 0, for each attachment point to which this
1746 // image was attached in the currently bound framebuffer.
1747
1748 Framebuffer *framebuffer = getFramebuffer();
1749
1750 if (framebuffer)
1751 {
1752 framebuffer->detachTexture(texture);
1753 }
1754}
1755
1756void Context::detachFramebuffer(GLuint framebuffer)
1757{
1758 // [OpenGL ES 2.0.24] section 4.4 page 107:
1759 // If a framebuffer that is currently bound to the target FRAMEBUFFER is deleted, it is as though
1760 // BindFramebuffer had been executed with the target of FRAMEBUFFER and framebuffer of zero.
1761
1762 if (this->framebuffer == framebuffer)
1763 {
1764 bindFramebuffer(0);
1765 }
1766}
1767
1768void Context::detachRenderbuffer(GLuint renderbuffer)
1769{
1770 // [OpenGL ES 2.0.24] section 4.4 page 109:
1771 // If a renderbuffer that is currently bound to RENDERBUFFER is deleted, it is as though BindRenderbuffer
1772 // had been executed with the target RENDERBUFFER and name of zero.
1773
1774 if (this->renderbuffer == renderbuffer)
1775 {
1776 bindRenderbuffer(0);
1777 }
1778
1779 // [OpenGL ES 2.0.24] section 4.4 page 111:
1780 // If a renderbuffer object is deleted while its image is attached to the currently bound framebuffer,
1781 // then it is as if FramebufferRenderbuffer had been called, with a renderbuffer of 0, for each attachment
1782 // point to which this image was attached in the currently bound framebuffer.
1783
1784 Framebuffer *framebuffer = getFramebuffer();
1785
1786 if (framebuffer)
1787 {
1788 framebuffer->detachRenderbuffer(renderbuffer);
1789 }
1790}
1791}
1792
1793extern "C"
1794{
1795gl::Context *glCreateContext(const egl::Config *config)
1796{
1797 return new gl::Context(config);
1798}
1799
1800void glDestroyContext(gl::Context *context)
1801{
1802 delete context;
1803
1804 if (context == gl::getContext())
1805 {
1806 gl::makeCurrent(NULL, NULL, NULL);
1807 }
1808}
1809
1810void glMakeCurrent(gl::Context *context, egl::Display *display, egl::Surface *surface)
1811{
1812 gl::makeCurrent(context, display, surface);
1813}
1814
1815gl::Context *glGetCurrentContext()
1816{
1817 return gl::getContext();
1818}
1819}