blob: 9aada338c432346b9c6ccabaa464bf7be06fbbc0 [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
795 GLuint halfPixelSize = programObject->getUniformLocation("gl_HalfPixelSize");
796 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
799 GLuint near = programObject->getUniformLocation("gl_DepthRange.near");
800 programObject->setUniform1fv(near, 1, &zNear);
801
802 GLuint far = programObject->getUniformLocation("gl_DepthRange.far");
803 programObject->setUniform1fv(far, 1, &zFar);
804
805 GLuint diff = programObject->getUniformLocation("gl_DepthRange.diff");
806 GLfloat zDiff = zFar - zNear;
807 programObject->setUniform1fv(diff, 1, &zDiff);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000808 }
809
810 return true;
811}
812
813// Applies the fixed-function state (culling, depth test, alpha blending, stenciling, etc) to the Direct3D 9 device
814void Context::applyState()
815{
816 IDirect3DDevice9 *device = getDevice();
817
818 if (cullFace)
819 {
820 device->SetRenderState(D3DRS_CULLMODE, es2dx::ConvertCullMode(cullMode, frontFace));
821 }
822 else
823 {
824 device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
825 }
826
827 if (depthTest)
828 {
829 device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
830 device->SetRenderState(D3DRS_ZFUNC, es2dx::ConvertComparison(depthFunc));
831 }
832 else
833 {
834 device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
835 }
836
837 if (blend)
838 {
839 device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
840
841 if (sourceBlendRGB != GL_CONSTANT_ALPHA && sourceBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA &&
842 destBlendRGB != GL_CONSTANT_ALPHA && destBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA)
843 {
844 device->SetRenderState(D3DRS_BLENDFACTOR, es2dx::ConvertColor(blendColor));
845 }
846 else
847 {
848 device->SetRenderState(D3DRS_BLENDFACTOR, D3DCOLOR_RGBA(unorm<8>(blendColor.alpha),
849 unorm<8>(blendColor.alpha),
850 unorm<8>(blendColor.alpha),
851 unorm<8>(blendColor.alpha)));
852 }
853
854 device->SetRenderState(D3DRS_SRCBLEND, es2dx::ConvertBlendFunc(sourceBlendRGB));
855 device->SetRenderState(D3DRS_DESTBLEND, es2dx::ConvertBlendFunc(destBlendRGB));
856 device->SetRenderState(D3DRS_BLENDOP, es2dx::ConvertBlendOp(blendEquationRGB));
857
858 if (sourceBlendRGB != sourceBlendAlpha || destBlendRGB != destBlendAlpha || blendEquationRGB != blendEquationAlpha)
859 {
860 device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
861
862 device->SetRenderState(D3DRS_SRCBLENDALPHA, es2dx::ConvertBlendFunc(sourceBlendAlpha));
863 device->SetRenderState(D3DRS_DESTBLENDALPHA, es2dx::ConvertBlendFunc(destBlendAlpha));
864 device->SetRenderState(D3DRS_BLENDOPALPHA, es2dx::ConvertBlendOp(blendEquationAlpha));
865
866 }
867 else
868 {
869 device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
870 }
871 }
872 else
873 {
874 device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
875 }
876
877 if (stencilTest)
878 {
879 device->SetRenderState(D3DRS_STENCILENABLE, TRUE);
880 device->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE);
881
882 // FIXME: Unsupported by D3D9
883 const D3DRENDERSTATETYPE D3DRS_CCW_STENCILREF = D3DRS_STENCILREF;
884 const D3DRENDERSTATETYPE D3DRS_CCW_STENCILMASK = D3DRS_STENCILMASK;
885 const D3DRENDERSTATETYPE D3DRS_CCW_STENCILWRITEMASK = D3DRS_STENCILWRITEMASK;
886 ASSERT(stencilRef == stencilBackRef);
887 ASSERT(stencilMask == stencilBackMask);
888 ASSERT(stencilWritemask == stencilBackWritemask);
889
890 device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, stencilWritemask);
891 device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, es2dx::ConvertComparison(stencilFunc));
892
893 device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, stencilRef); // FIXME: Clamp to range
894 device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, stencilMask);
895
896 device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, es2dx::ConvertStencilOp(stencilFail));
897 device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, es2dx::ConvertStencilOp(stencilPassDepthFail));
898 device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, es2dx::ConvertStencilOp(stencilPassDepthPass));
899
900 device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, stencilBackWritemask);
901 device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, es2dx::ConvertComparison(stencilBackFunc));
902
903 device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, stencilBackRef); // FIXME: Clamp to range
904 device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, stencilBackMask);
905
906 device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, es2dx::ConvertStencilOp(stencilBackFail));
907 device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, es2dx::ConvertStencilOp(stencilBackPassDepthFail));
908 device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, es2dx::ConvertStencilOp(stencilBackPassDepthPass));
909 }
910 else
911 {
912 device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
913 }
914
915 device->SetRenderState(D3DRS_COLORWRITEENABLE, es2dx::ConvertColorMask(colorMaskRed, colorMaskGreen, colorMaskBlue, colorMaskAlpha));
916 device->SetRenderState(D3DRS_ZWRITEENABLE, depthMask ? TRUE : FALSE);
917
918 if (polygonOffsetFill)
919 {
920 UNIMPLEMENTED(); // FIXME
921 }
922
923 if (sampleAlphaToCoverage)
924 {
925 UNIMPLEMENTED(); // FIXME
926 }
927
928 if (sampleCoverage)
929 {
930 UNIMPLEMENTED(); // FIXME: Ignore when SAMPLE_BUFFERS is not one
931 }
932
933 device->SetRenderState(D3DRS_DITHERENABLE, dither ? TRUE : FALSE);
934}
935
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000936// Fill in the programAttribute field of the array of TranslatedAttributes based on the active GLSL program.
937void Context::lookupAttributeMapping(TranslatedAttribute *attributes)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000938{
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000939 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000940 {
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000941 if (attributes[i].enabled)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000942 {
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000943 attributes[i].programAttribute = getCurrentProgram()->getInputMapping(i);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000944 }
945 }
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000946}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000947
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000948// The indices parameter to glDrawElements can have two interpretations:
949// - as a pointer into client memory
950// - as an offset into the current GL_ELEMENT_ARRAY_BUFFER buffer
951// Handle these cases here and return a pointer to the index data.
952const Index *Context::adjustIndexPointer(const void *indices)
953{
954 if (elementArrayBuffer)
955 {
956 Buffer *buffer = getBuffer(elementArrayBuffer);
957 return reinterpret_cast<const Index*>(static_cast<unsigned char*>(buffer->data()) + reinterpret_cast<GLsizei>(indices));
958 }
959 else
960 {
961 return static_cast<const Index*>(indices);
962 }
963}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000964
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000965void Context::applyVertexBuffer(GLint first, GLsizei count)
966{
967 TranslatedAttribute translated[MAX_VERTEX_ATTRIBS];
968
969 mVertexDataManager->preRenderValidate(first, count, translated);
970
971 lookupAttributeMapping(translated);
972
973 mBufferBackEnd->preDraw(translated);
974}
975
976void Context::applyVertexBuffer(GLsizei count, const void *indices, GLenum indexType)
977{
978 TranslatedAttribute translated[MAX_VERTEX_ATTRIBS];
979
980 mVertexDataManager->preRenderValidate(adjustIndexPointer(indices), count, translated);
981
982 lookupAttributeMapping(translated);
983
984 mBufferBackEnd->preDraw(translated);
985}
986
987// Applies the indices and element array bindings to the Direct3D 9 device
988void Context::applyIndexBuffer(const void *indices, GLsizei count)
989{
990 GLsizei length = count * sizeof(Index);
991
992 IDirect3DDevice9 *device = getDevice();
993
994 IDirect3DIndexBuffer9 *indexBuffer = NULL;
995 void *data;
996
997 HRESULT result = device->CreateIndexBuffer(length, 0, D3DFMT_INDEX16, D3DPOOL_MANAGED, &indexBuffer, NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000998
999 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
1000 {
1001 return error(GL_OUT_OF_MEMORY);
1002 }
1003
1004 ASSERT(SUCCEEDED(result));
1005
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +00001006 if (indexBuffer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001007 {
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +00001008 indexBuffer->Lock(0, length, &data, 0);
1009 memcpy(data, adjustIndexPointer(indices), length);
1010 indexBuffer->Unlock();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001011
1012 device->SetIndices(indexBuffer);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +00001013 indexBuffer->Release(); // Will only effectively be deleted when no longer in use
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001014 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001015
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +00001016 startIndex = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001017}
1018
1019// Applies the shaders and shader constants to the Direct3D 9 device
1020void Context::applyShaders()
1021{
1022 IDirect3DDevice9 *device = getDevice();
1023 Program *programObject = getCurrentProgram();
1024 IDirect3DVertexShader9 *vertexShader = programObject->getVertexShader();
1025 IDirect3DPixelShader9 *pixelShader = programObject->getPixelShader();
1026
1027 device->SetVertexShader(vertexShader);
1028 device->SetPixelShader(pixelShader);
1029
1030 programObject->applyUniforms();
1031}
1032
1033// Applies the textures and sampler states to the Direct3D 9 device
1034void Context::applyTextures()
1035{
1036 IDirect3DDevice9 *device = getDevice();
1037 Program *programObject = getCurrentProgram();
1038
1039 for (int sampler = 0; sampler < MAX_TEXTURE_IMAGE_UNITS; sampler++)
1040 {
1041 unsigned int textureUnit = programObject->getSamplerMapping(sampler);
1042 Texture *texture = getSamplerTexture(textureUnit);
1043
1044 if (texture && texture->isComplete())
1045 {
1046 GLenum wrapS = texture->getWrapS();
1047 GLenum wrapT = texture->getWrapT();
1048 GLenum minFilter = texture->getMinFilter();
1049 GLenum magFilter = texture->getMagFilter();
1050
1051 device->SetSamplerState(sampler, D3DSAMP_ADDRESSU, es2dx::ConvertTextureWrap(wrapS));
1052 device->SetSamplerState(sampler, D3DSAMP_ADDRESSV, es2dx::ConvertTextureWrap(wrapT));
1053
1054 device->SetSamplerState(sampler, D3DSAMP_MAGFILTER, es2dx::ConvertMagFilter(magFilter));
1055 D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter;
1056 es2dx::ConvertMinFilter(minFilter, &d3dMinFilter, &d3dMipFilter);
1057 device->SetSamplerState(sampler, D3DSAMP_MINFILTER, d3dMinFilter);
1058 device->SetSamplerState(sampler, D3DSAMP_MIPFILTER, d3dMipFilter);
1059
1060 device->SetTexture(sampler, texture->getTexture());
1061 }
1062 }
1063}
1064
1065void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels)
1066{
1067 Framebuffer *framebuffer = getFramebuffer();
1068 IDirect3DSurface9 *renderTarget = framebuffer->getRenderTarget();
1069 IDirect3DDevice9 *device = getDevice();
1070
1071 D3DSURFACE_DESC desc;
1072 renderTarget->GetDesc(&desc);
1073
1074 IDirect3DSurface9 *systemSurface;
1075 HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &systemSurface, NULL);
1076
1077 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
1078 {
1079 return error(GL_OUT_OF_MEMORY);
1080 }
1081
1082 ASSERT(SUCCEEDED(result));
1083
1084 if (desc.MultiSampleType != D3DMULTISAMPLE_NONE)
1085 {
1086 UNIMPLEMENTED(); // FIXME: Requires resolve using StretchRect into non-multisampled render target
1087 }
1088
1089 result = device->GetRenderTargetData(renderTarget, systemSurface);
1090
1091 if (result == D3DERR_DRIVERINTERNALERROR)
1092 {
1093 systemSurface->Release();
1094
1095 return error(GL_OUT_OF_MEMORY);
1096 }
1097
1098 if (FAILED(result))
1099 {
1100 UNREACHABLE();
1101 systemSurface->Release();
1102
1103 return; // No sensible error to generate
1104 }
1105
1106 D3DLOCKED_RECT lock;
daniel@transgaming.com16973022010-03-11 19:22:19 +00001107 RECT rect = {std::max(x, 0),
1108 std::max(y, 0),
1109 std::min(x + width, (int)desc.Width),
1110 std::min(y + height, (int)desc.Height)};
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001111
1112 result = systemSurface->LockRect(&lock, &rect, D3DLOCK_READONLY);
1113
1114 if (FAILED(result))
1115 {
1116 UNREACHABLE();
1117 systemSurface->Release();
1118
1119 return; // No sensible error to generate
1120 }
1121
1122 unsigned char *source = (unsigned char*)lock.pBits;
1123 unsigned char *dest = (unsigned char*)pixels;
1124
1125 for (int j = 0; j < rect.bottom - rect.top; j++)
1126 {
1127 for (int i = 0; i < rect.right - rect.left; i++)
1128 {
1129 float r;
1130 float g;
1131 float b;
1132 float a;
1133
1134 switch (desc.Format)
1135 {
1136 case D3DFMT_R5G6B5:
1137 {
1138 unsigned short rgb = *(unsigned short*)(source + 2 * i + j * lock.Pitch);
1139
1140 a = 1.0f;
1141 b = (rgb & 0x001F) * (1.0f / 0x001F);
1142 g = (rgb & 0x07E0) * (1.0f / 0x07E0);
1143 r = (rgb & 0xF800) * (1.0f / 0xF800);
1144 }
1145 break;
1146 case D3DFMT_X1R5G5B5:
1147 {
1148 unsigned short xrgb = *(unsigned short*)(source + 2 * i + j * lock.Pitch);
1149
1150 a = 1.0f;
1151 b = (xrgb & 0x001F) * (1.0f / 0x001F);
1152 g = (xrgb & 0x03E0) * (1.0f / 0x03E0);
1153 r = (xrgb & 0x7C00) * (1.0f / 0x7C00);
1154 }
1155 break;
1156 case D3DFMT_A1R5G5B5:
1157 {
1158 unsigned short argb = *(unsigned short*)(source + 2 * i + j * lock.Pitch);
1159
1160 a = (argb & 0x8000) ? 1.0f : 0.0f;
1161 b = (argb & 0x001F) * (1.0f / 0x001F);
1162 g = (argb & 0x03E0) * (1.0f / 0x03E0);
1163 r = (argb & 0x7C00) * (1.0f / 0x7C00);
1164 }
1165 break;
1166 case D3DFMT_A8R8G8B8:
1167 {
1168 unsigned int argb = *(unsigned int*)(source + 4 * i + j * lock.Pitch);
1169
1170 a = (argb & 0xFF000000) * (1.0f / 0xFF000000);
1171 b = (argb & 0x000000FF) * (1.0f / 0x000000FF);
1172 g = (argb & 0x0000FF00) * (1.0f / 0x0000FF00);
1173 r = (argb & 0x00FF0000) * (1.0f / 0x00FF0000);
1174 }
1175 break;
1176 case D3DFMT_X8R8G8B8:
1177 {
1178 unsigned int xrgb = *(unsigned int*)(source + 4 * i + j * lock.Pitch);
1179
1180 a = 1.0f;
1181 b = (xrgb & 0x000000FF) * (1.0f / 0x000000FF);
1182 g = (xrgb & 0x0000FF00) * (1.0f / 0x0000FF00);
1183 r = (xrgb & 0x00FF0000) * (1.0f / 0x00FF0000);
1184 }
1185 break;
1186 case D3DFMT_A2R10G10B10:
1187 {
1188 unsigned int argb = *(unsigned int*)(source + 4 * i + j * lock.Pitch);
1189
1190 a = (argb & 0xC0000000) * (1.0f / 0xC0000000);
1191 b = (argb & 0x000003FF) * (1.0f / 0x000003FF);
1192 g = (argb & 0x000FFC00) * (1.0f / 0x000FFC00);
1193 r = (argb & 0x3FF00000) * (1.0f / 0x3FF00000);
1194 }
1195 break;
1196 default:
1197 UNIMPLEMENTED(); // FIXME
1198 UNREACHABLE();
1199 }
1200
1201 switch (format)
1202 {
1203 case GL_RGBA:
1204 switch (type)
1205 {
1206 case GL_UNSIGNED_BYTE:
1207 dest[4 * (i + j * width) + 0] = (unsigned char)(255 * r + 0.5f);
1208 dest[4 * (i + j * width) + 1] = (unsigned char)(255 * g + 0.5f);
1209 dest[4 * (i + j * width) + 2] = (unsigned char)(255 * b + 0.5f);
1210 dest[4 * (i + j * width) + 3] = (unsigned char)(255 * a + 0.5f);
1211 break;
1212 default: UNREACHABLE();
1213 }
1214 break;
1215 case IMPLEMENTATION_COLOR_READ_FORMAT:
1216 switch (type)
1217 {
1218 case IMPLEMENTATION_COLOR_READ_TYPE:
1219 break;
1220 default: UNREACHABLE();
1221 }
1222 break;
1223 default: UNREACHABLE();
1224 }
1225 }
1226 }
1227
1228 systemSurface->UnlockRect();
1229
1230 systemSurface->Release();
1231}
1232
1233void Context::clear(GLbitfield mask)
1234{
1235 IDirect3DDevice9 *device = getDevice();
1236 DWORD flags = 0;
1237
1238 if (mask & GL_COLOR_BUFFER_BIT)
1239 {
1240 mask &= ~GL_COLOR_BUFFER_BIT;
1241 flags |= D3DCLEAR_TARGET;
1242 }
1243
1244 if (mask & GL_DEPTH_BUFFER_BIT)
1245 {
1246 mask &= ~GL_DEPTH_BUFFER_BIT;
1247 if (depthMask)
1248 {
1249 flags |= D3DCLEAR_ZBUFFER;
1250 }
1251 }
1252
1253 Framebuffer *framebufferObject = getFramebuffer();
1254 IDirect3DSurface9 *depthStencil = framebufferObject->getDepthStencil();
1255
1256 GLuint stencilUnmasked = 0x0;
1257
1258 if ((mask & GL_STENCIL_BUFFER_BIT) && depthStencil)
1259 {
1260 D3DSURFACE_DESC desc;
1261 depthStencil->GetDesc(&desc);
1262
1263 mask &= ~GL_STENCIL_BUFFER_BIT;
1264 unsigned int stencilSize = es2dx::GetStencilSize(desc.Format);
1265 stencilUnmasked = (0x1 << stencilSize) - 1;
1266
1267 if (stencilUnmasked != 0x0)
1268 {
1269 flags |= D3DCLEAR_STENCIL;
1270 }
1271 }
1272
1273 if (mask != 0)
1274 {
1275 return error(GL_INVALID_VALUE);
1276 }
1277
1278 applyRenderTarget(true); // Clips the clear to the scissor rectangle but not the viewport
1279
1280 D3DCOLOR color = D3DCOLOR_ARGB(unorm<8>(colorClearValue.alpha), unorm<8>(colorClearValue.red), unorm<8>(colorClearValue.green), unorm<8>(colorClearValue.blue));
1281 float depth = clamp01(depthClearValue);
1282 int stencil = stencilClearValue & 0x000000FF;
1283
1284 IDirect3DSurface9 *renderTarget = framebufferObject->getRenderTarget();
1285
1286 D3DSURFACE_DESC desc;
1287 renderTarget->GetDesc(&desc);
1288
1289 bool alphaUnmasked = (es2dx::GetAlphaSize(desc.Format) == 0) || colorMaskAlpha;
1290
1291 const bool needMaskedStencilClear = (flags & D3DCLEAR_STENCIL) &&
1292 (stencilWritemask & stencilUnmasked) != stencilUnmasked;
1293 const bool needMaskedColorClear = (flags & D3DCLEAR_TARGET) &&
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001294 !(colorMaskRed && colorMaskGreen &&
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001295 colorMaskBlue && alphaUnmasked);
1296
1297 if (needMaskedColorClear || needMaskedStencilClear)
1298 {
1299 device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
1300 device->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
1301 device->SetRenderState(D3DRS_ZENABLE, FALSE);
1302 device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
1303 device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
1304 device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
1305 device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
1306 device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
1307
1308 if (flags & D3DCLEAR_TARGET)
1309 {
1310 device->SetRenderState(D3DRS_COLORWRITEENABLE, (colorMaskRed ? D3DCOLORWRITEENABLE_RED : 0) |
1311 (colorMaskGreen ? D3DCOLORWRITEENABLE_GREEN : 0) |
1312 (colorMaskBlue ? D3DCOLORWRITEENABLE_BLUE : 0) |
1313 (colorMaskAlpha ? D3DCOLORWRITEENABLE_ALPHA : 0));
1314 }
1315 else
1316 {
1317 device->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
1318 }
1319
1320 if (stencilUnmasked != 0x0 && (flags & D3DCLEAR_STENCIL))
1321 {
1322 device->SetRenderState(D3DRS_STENCILENABLE, TRUE);
1323 device->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
1324 device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);
1325 device->SetRenderState(D3DRS_STENCILREF, stencil);
1326 device->SetRenderState(D3DRS_STENCILWRITEMASK, stencilWritemask);
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001327 device->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001328 device->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_REPLACE);
1329 device->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE);
1330 }
1331 else
1332 {
1333 device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
1334 }
1335
1336 device->SetPixelShader(NULL);
1337 device->SetVertexShader(NULL);
1338 device->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
1339
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001340 struct Vertex
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001341 {
1342 float x, y, z, w;
1343 D3DCOLOR diffuse;
1344 };
1345
1346 Vertex quad[4];
1347 quad[0].x = 0.0f;
1348 quad[0].y = (float)desc.Height;
1349 quad[0].z = 0.0f;
1350 quad[0].w = 1.0f;
1351 quad[0].diffuse = color;
1352
1353 quad[1].x = (float)desc.Width;
1354 quad[1].y = (float)desc.Height;
1355 quad[1].z = 0.0f;
1356 quad[1].w = 1.0f;
1357 quad[1].diffuse = color;
1358
1359 quad[2].x = 0.0f;
1360 quad[2].y = 0.0f;
1361 quad[2].z = 0.0f;
1362 quad[2].w = 1.0f;
1363 quad[2].diffuse = color;
1364
1365 quad[3].x = (float)desc.Width;
1366 quad[3].y = 0.0f;
1367 quad[3].z = 0.0f;
1368 quad[3].w = 1.0f;
1369 quad[3].diffuse = color;
1370
1371 device->BeginScene();
1372 device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(Vertex));
1373 device->EndScene();
1374
1375 if (flags & D3DCLEAR_ZBUFFER)
1376 {
1377 device->SetRenderState(D3DRS_ZENABLE, TRUE);
1378 device->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
1379 device->Clear(0, NULL, D3DCLEAR_ZBUFFER, color, depth, stencil);
1380 }
1381 }
1382 else
1383 {
1384 device->Clear(0, NULL, flags, color, depth, stencil);
1385 }
1386}
1387
1388void Context::drawArrays(GLenum mode, GLint first, GLsizei count)
1389{
1390 if (!currentProgram)
1391 {
1392 return error(GL_INVALID_OPERATION);
1393 }
1394
1395 IDirect3DDevice9 *device = getDevice();
1396 D3DPRIMITIVETYPE primitiveType;
1397 int primitiveCount;
1398
1399 if(!es2dx::ConvertPrimitiveType(mode, count, &primitiveType, &primitiveCount))
1400 return error(GL_INVALID_ENUM);
1401
1402 if (primitiveCount <= 0)
1403 {
1404 return;
1405 }
1406
1407 if (!applyRenderTarget(false))
1408 {
1409 return error(GL_INVALID_FRAMEBUFFER_OPERATION);
1410 }
1411
1412 applyState();
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +00001413 applyVertexBuffer(first, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001414 applyShaders();
1415 applyTextures();
1416
1417 device->BeginScene();
1418 device->DrawPrimitive(primitiveType, first, primitiveCount);
1419 device->EndScene();
1420}
1421
1422void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const void* indices)
1423{
1424 if (!currentProgram)
1425 {
1426 return error(GL_INVALID_OPERATION);
1427 }
1428
1429 if (!indices && !elementArrayBuffer)
1430 {
1431 return error(GL_INVALID_OPERATION);
1432 }
1433
1434 IDirect3DDevice9 *device = getDevice();
1435 D3DPRIMITIVETYPE primitiveType;
1436 int primitiveCount;
1437
1438 if(!es2dx::ConvertPrimitiveType(mode, count, &primitiveType, &primitiveCount))
1439 return error(GL_INVALID_ENUM);
1440
1441 if (primitiveCount <= 0)
1442 {
1443 return;
1444 }
1445
1446 if (!applyRenderTarget(false))
1447 {
1448 return error(GL_INVALID_FRAMEBUFFER_OPERATION);
1449 }
1450
1451 applyState();
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +00001452 applyVertexBuffer(count, indices, type);
1453 applyIndexBuffer(indices, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001454 applyShaders();
1455 applyTextures();
1456
1457 device->BeginScene();
1458 device->DrawIndexedPrimitive(primitiveType, 0, 0, count, startIndex, primitiveCount);
1459 device->EndScene();
1460}
1461
1462void Context::finish()
1463{
1464 IDirect3DDevice9 *device = getDevice();
1465 IDirect3DQuery9 *occlusionQuery = NULL;
1466
1467 HRESULT result = device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery);
1468
1469 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
1470 {
1471 return error(GL_OUT_OF_MEMORY);
1472 }
1473
1474 ASSERT(SUCCEEDED(result));
1475
1476 if (occlusionQuery)
1477 {
1478 occlusionQuery->Issue(D3DISSUE_BEGIN);
1479
1480 // Render something outside the render target
1481 device->SetPixelShader(NULL);
1482 device->SetVertexShader(NULL);
1483 device->SetFVF(D3DFVF_XYZRHW);
1484 float data[4] = {-1.0f, -1.0f, -1.0f, 1.0f};
1485 device->BeginScene();
1486 device->DrawPrimitiveUP(D3DPT_POINTLIST, 1, data, sizeof(data));
1487 device->EndScene();
1488
1489 occlusionQuery->Issue(D3DISSUE_END);
1490
1491 while (occlusionQuery->GetData(NULL, 0, D3DGETDATA_FLUSH) == S_FALSE)
1492 {
1493 // Keep polling, but allow other threads to do something useful first
1494 Sleep(0);
1495 }
1496
1497 occlusionQuery->Release();
1498 }
1499}
1500
1501void Context::flush()
1502{
1503 IDirect3DDevice9 *device = getDevice();
1504 IDirect3DQuery9 *eventQuery = NULL;
1505
1506 HRESULT result = device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery);
1507
1508 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
1509 {
1510 return error(GL_OUT_OF_MEMORY);
1511 }
1512
1513 ASSERT(SUCCEEDED(result));
1514
1515 if (eventQuery)
1516 {
1517 eventQuery->Issue(D3DISSUE_END);
1518
1519 while (eventQuery->GetData(NULL, 0, D3DGETDATA_FLUSH) == S_FALSE)
1520 {
1521 // Keep polling, but allow other threads to do something useful first
1522 Sleep(0);
1523 }
1524
1525 eventQuery->Release();
1526 }
1527}
1528
1529void Context::recordInvalidEnum()
1530{
1531 mInvalidEnum = true;
1532}
1533
1534void Context::recordInvalidValue()
1535{
1536 mInvalidValue = true;
1537}
1538
1539void Context::recordInvalidOperation()
1540{
1541 mInvalidOperation = true;
1542}
1543
1544void Context::recordOutOfMemory()
1545{
1546 mOutOfMemory = true;
1547}
1548
1549void Context::recordInvalidFramebufferOperation()
1550{
1551 mInvalidFramebufferOperation = true;
1552}
1553
1554// Get one of the recorded errors and clear its flag, if any.
1555// [OpenGL ES 2.0.24] section 2.5 page 13.
1556GLenum Context::getError()
1557{
1558 if (mInvalidEnum)
1559 {
1560 mInvalidEnum = false;
1561
1562 return GL_INVALID_ENUM;
1563 }
1564
1565 if (mInvalidValue)
1566 {
1567 mInvalidValue = false;
1568
1569 return GL_INVALID_VALUE;
1570 }
1571
1572 if (mInvalidOperation)
1573 {
1574 mInvalidOperation = false;
1575
1576 return GL_INVALID_OPERATION;
1577 }
1578
1579 if (mOutOfMemory)
1580 {
1581 mOutOfMemory = false;
1582
1583 return GL_OUT_OF_MEMORY;
1584 }
1585
1586 if (mInvalidFramebufferOperation)
1587 {
1588 mInvalidFramebufferOperation = false;
1589
1590 return GL_INVALID_FRAMEBUFFER_OPERATION;
1591 }
1592
1593 return GL_NO_ERROR;
1594}
1595
1596void Context::detachBuffer(GLuint buffer)
1597{
1598 // [OpenGL ES 2.0.24] section 2.9 page 22:
1599 // If a buffer object is deleted while it is bound, all bindings to that object in the current context
1600 // (i.e. in the thread that called Delete-Buffers) are reset to zero.
1601
1602 if (arrayBuffer == buffer)
1603 {
1604 arrayBuffer = 0;
1605 }
1606
1607 if (elementArrayBuffer == buffer)
1608 {
1609 elementArrayBuffer = 0;
1610 }
1611
1612 for (int attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
1613 {
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +00001614 if (vertexAttribute[attribute].mBoundBuffer == buffer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001615 {
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +00001616 vertexAttribute[attribute].mBoundBuffer = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001617 }
1618 }
1619}
1620
1621void Context::detachTexture(GLuint texture)
1622{
1623 // [OpenGL ES 2.0.24] section 3.8 page 84:
1624 // If a texture object is deleted, it is as if all texture units which are bound to that texture object are
1625 // rebound to texture object zero
1626
1627 for (int sampler = 0; sampler < MAX_TEXTURE_IMAGE_UNITS; sampler++)
1628 {
1629 if (samplerTexture[sampler] == texture)
1630 {
1631 samplerTexture[sampler] = 0;
1632 }
1633 }
1634
1635 // [OpenGL ES 2.0.24] section 4.4 page 112:
1636 // If a texture object is deleted while its image is attached to the currently bound framebuffer, then it is
1637 // as if FramebufferTexture2D had been called, with a texture of 0, for each attachment point to which this
1638 // image was attached in the currently bound framebuffer.
1639
1640 Framebuffer *framebuffer = getFramebuffer();
1641
1642 if (framebuffer)
1643 {
1644 framebuffer->detachTexture(texture);
1645 }
1646}
1647
1648void Context::detachFramebuffer(GLuint framebuffer)
1649{
1650 // [OpenGL ES 2.0.24] section 4.4 page 107:
1651 // If a framebuffer that is currently bound to the target FRAMEBUFFER is deleted, it is as though
1652 // BindFramebuffer had been executed with the target of FRAMEBUFFER and framebuffer of zero.
1653
1654 if (this->framebuffer == framebuffer)
1655 {
1656 bindFramebuffer(0);
1657 }
1658}
1659
1660void Context::detachRenderbuffer(GLuint renderbuffer)
1661{
1662 // [OpenGL ES 2.0.24] section 4.4 page 109:
1663 // If a renderbuffer that is currently bound to RENDERBUFFER is deleted, it is as though BindRenderbuffer
1664 // had been executed with the target RENDERBUFFER and name of zero.
1665
1666 if (this->renderbuffer == renderbuffer)
1667 {
1668 bindRenderbuffer(0);
1669 }
1670
1671 // [OpenGL ES 2.0.24] section 4.4 page 111:
1672 // If a renderbuffer object is deleted while its image is attached to the currently bound framebuffer,
1673 // then it is as if FramebufferRenderbuffer had been called, with a renderbuffer of 0, for each attachment
1674 // point to which this image was attached in the currently bound framebuffer.
1675
1676 Framebuffer *framebuffer = getFramebuffer();
1677
1678 if (framebuffer)
1679 {
1680 framebuffer->detachRenderbuffer(renderbuffer);
1681 }
1682}
1683}
1684
1685extern "C"
1686{
1687gl::Context *glCreateContext(const egl::Config *config)
1688{
1689 return new gl::Context(config);
1690}
1691
1692void glDestroyContext(gl::Context *context)
1693{
1694 delete context;
1695
1696 if (context == gl::getContext())
1697 {
1698 gl::makeCurrent(NULL, NULL, NULL);
1699 }
1700}
1701
1702void glMakeCurrent(gl::Context *context, egl::Display *display, egl::Surface *surface)
1703{
1704 gl::makeCurrent(context, display, surface);
1705}
1706
1707gl::Context *glGetCurrentContext()
1708{
1709 return gl::getContext();
1710}
1711}