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