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