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