blob: 6fc2cd4e803138de9669eb4390ef17b311a91572 [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
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000118 for (int type = 0; type < SAMPLER_TYPE_COUNT; type++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000119 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000120 for (int sampler = 0; sampler < MAX_TEXTURE_IMAGE_UNITS; sampler++)
121 {
122 samplerTexture[type][sampler] = 0;
123 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000124 }
125
daniel@transgaming.com12d54072010-03-16 06:23:26 +0000126 for (int type = 0; type < SAMPLER_TYPE_COUNT; type++)
127 {
128 mIncompleteTextures[type] = NULL;
129 }
130
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000131 currentProgram = 0;
132
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000133 mBufferBackEnd = NULL;
134 mVertexDataManager = NULL;
135
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000136 mInvalidEnum = false;
137 mInvalidValue = false;
138 mInvalidOperation = false;
139 mOutOfMemory = false;
140 mInvalidFramebufferOperation = false;
141}
142
143Context::~Context()
144{
145 currentProgram = 0;
146
daniel@transgaming.com12d54072010-03-16 06:23:26 +0000147 for (int type = 0; type < SAMPLER_TYPE_COUNT; type++)
148 {
149 delete mIncompleteTextures[type];
150 }
151
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000152 delete mTexture2DZero;
153 delete mTextureCubeMapZero;
154
155 delete mColorbufferZero;
156 delete mDepthbufferZero;
157 delete mStencilbufferZero;
158
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000159 delete mBufferBackEnd;
160 delete mVertexDataManager;
161
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000162 while (!mBufferMap.empty())
163 {
164 deleteBuffer(mBufferMap.begin()->first);
165 }
166
167 while (!mProgramMap.empty())
168 {
169 deleteProgram(mProgramMap.begin()->first);
170 }
171
172 while (!mShaderMap.empty())
173 {
174 deleteShader(mShaderMap.begin()->first);
175 }
176
177 while (!mFramebufferMap.empty())
178 {
179 deleteFramebuffer(mFramebufferMap.begin()->first);
180 }
181
182 while (!mRenderbufferMap.empty())
183 {
184 deleteRenderbuffer(mRenderbufferMap.begin()->first);
185 }
186
187 while (!mTextureMap.empty())
188 {
189 deleteTexture(mTextureMap.begin()->first);
190 }
191}
192
193void Context::makeCurrent(egl::Display *display, egl::Surface *surface)
194{
195 IDirect3DDevice9 *device = display->getDevice();
196
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000197 if (!mBufferBackEnd)
198 {
199 mBufferBackEnd = new Dx9BackEnd(device);
200 mVertexDataManager = new VertexDataManager(this, mBufferBackEnd);
201 }
202
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000203 // Wrap the existing Direct3D 9 resources into GL objects and assign them to the '0' names
204 IDirect3DSurface9 *defaultRenderTarget = surface->getRenderTarget();
205 IDirect3DSurface9 *defaultDepthStencil = NULL;
206 device->GetDepthStencilSurface(&defaultDepthStencil);
207
208 Framebuffer *framebufferZero = new Framebuffer();
209 Colorbuffer *colorbufferZero = new Colorbuffer(defaultRenderTarget);
210 Depthbuffer *depthbufferZero = new Depthbuffer(defaultDepthStencil);
211 Stencilbuffer *stencilbufferZero = new Stencilbuffer(defaultDepthStencil);
212
213 setFramebufferZero(framebufferZero);
214 setColorbufferZero(colorbufferZero);
215 setDepthbufferZero(depthbufferZero);
216 setStencilbufferZero(stencilbufferZero);
217
218 framebufferZero->setColorbuffer(GL_RENDERBUFFER, 0);
219 framebufferZero->setDepthbuffer(GL_RENDERBUFFER, 0);
220 framebufferZero->setStencilbuffer(GL_RENDERBUFFER, 0);
221
222 defaultRenderTarget->Release();
223
224 if (defaultDepthStencil)
225 {
226 defaultDepthStencil->Release();
227 }
228}
229
230void Context::setClearColor(float red, float green, float blue, float alpha)
231{
232 colorClearValue.red = red;
233 colorClearValue.green = green;
234 colorClearValue.blue = blue;
235 colorClearValue.alpha = alpha;
236}
237
238void Context::setClearDepth(float depth)
239{
240 depthClearValue = depth;
241}
242
243void Context::setClearStencil(int stencil)
244{
245 stencilClearValue = stencil;
246}
247
248// Returns an unused buffer name
249GLuint Context::createBuffer()
250{
251 unsigned int handle = 1;
252
253 while (mBufferMap.find(handle) != mBufferMap.end())
254 {
255 handle++;
256 }
257
258 mBufferMap[handle] = NULL;
259
260 return handle;
261}
262
263// Returns an unused shader/program name
264GLuint Context::createShader(GLenum type)
265{
266 unsigned int handle = 1;
267
268 while (mShaderMap.find(handle) != mShaderMap.end() || mProgramMap.find(handle) != mProgramMap.end()) // Shared name space
269 {
270 handle++;
271 }
272
273 if (type == GL_VERTEX_SHADER)
274 {
275 mShaderMap[handle] = new VertexShader();
276 }
277 else if (type == GL_FRAGMENT_SHADER)
278 {
279 mShaderMap[handle] = new FragmentShader();
280 }
281 else UNREACHABLE();
282
283 return handle;
284}
285
286// Returns an unused program/shader name
287GLuint Context::createProgram()
288{
289 unsigned int handle = 1;
290
291 while (mProgramMap.find(handle) != mProgramMap.end() || mShaderMap.find(handle) != mShaderMap.end()) // Shared name space
292 {
293 handle++;
294 }
295
296 mProgramMap[handle] = new Program();
297
298 return handle;
299}
300
301// Returns an unused texture name
302GLuint Context::createTexture()
303{
304 unsigned int handle = 1;
305
306 while (mTextureMap.find(handle) != mTextureMap.end())
307 {
308 handle++;
309 }
310
311 mTextureMap[handle] = NULL;
312
313 return handle;
314}
315
316// Returns an unused framebuffer name
317GLuint Context::createFramebuffer()
318{
319 unsigned int handle = 1;
320
321 while (mFramebufferMap.find(handle) != mFramebufferMap.end())
322 {
323 handle++;
324 }
325
326 mFramebufferMap[handle] = NULL;
327
328 return handle;
329}
330
331// Returns an unused renderbuffer name
332GLuint Context::createRenderbuffer()
333{
334 unsigned int handle = 1;
335
daniel@transgaming.come2b22122010-03-11 19:22:14 +0000336 while (mRenderbufferMap.find(handle) != mRenderbufferMap.end())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000337 {
338 handle++;
339 }
340
341 mRenderbufferMap[handle] = NULL;
342
343 return handle;
344}
345
346void Context::deleteBuffer(GLuint buffer)
347{
348 BufferMap::iterator bufferObject = mBufferMap.find(buffer);
349
350 if (bufferObject != mBufferMap.end())
351 {
352 detachBuffer(buffer);
353
354 delete bufferObject->second;
355 mBufferMap.erase(bufferObject);
356 }
357}
358
359void Context::deleteShader(GLuint shader)
360{
361 ShaderMap::iterator shaderObject = mShaderMap.find(shader);
362
363 if (shaderObject != mShaderMap.end())
364 {
365 if (!shaderObject->second->isAttached())
366 {
367 delete shaderObject->second;
368 mShaderMap.erase(shaderObject);
369 }
370 else
371 {
372 shaderObject->second->flagForDeletion();
373 }
374 }
375}
376
377void Context::deleteProgram(GLuint program)
378{
379 ProgramMap::iterator programObject = mProgramMap.find(program);
380
381 if (programObject != mProgramMap.end())
382 {
383 if (program != currentProgram)
384 {
385 delete programObject->second;
386 mProgramMap.erase(programObject);
387 }
388 else
389 {
390 programObject->second->flagForDeletion();
391 }
392 }
393}
394
395void Context::deleteTexture(GLuint texture)
396{
397 TextureMap::iterator textureObject = mTextureMap.find(texture);
398
399 if (textureObject != mTextureMap.end())
400 {
401 detachTexture(texture);
402
403 if (texture != 0)
404 {
405 delete textureObject->second;
406 }
407
408 mTextureMap.erase(textureObject);
409 }
410}
411
412void Context::deleteFramebuffer(GLuint framebuffer)
413{
414 FramebufferMap::iterator framebufferObject = mFramebufferMap.find(framebuffer);
415
416 if (framebufferObject != mFramebufferMap.end())
417 {
418 detachFramebuffer(framebuffer);
419
420 delete framebufferObject->second;
421 mFramebufferMap.erase(framebufferObject);
422 }
423}
424
425void Context::deleteRenderbuffer(GLuint renderbuffer)
426{
427 RenderbufferMap::iterator renderbufferObject = mRenderbufferMap.find(renderbuffer);
428
429 if (renderbufferObject != mRenderbufferMap.end())
430 {
431 detachRenderbuffer(renderbuffer);
432
433 delete renderbufferObject->second;
434 mRenderbufferMap.erase(renderbufferObject);
435 }
436}
437
438void Context::bindArrayBuffer(unsigned int buffer)
439{
440 if (buffer != 0 && !getBuffer(buffer))
441 {
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000442 mBufferMap[buffer] = new Buffer(mBufferBackEnd);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000443 }
444
445 arrayBuffer = buffer;
446}
447
448void Context::bindElementArrayBuffer(unsigned int buffer)
449{
450 if (buffer != 0 && !getBuffer(buffer))
451 {
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000452 mBufferMap[buffer] = new Buffer(mBufferBackEnd);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000453 }
454
455 elementArrayBuffer = buffer;
456}
457
458void Context::bindTexture2D(GLuint texture)
459{
460 if (!getTexture(texture) || texture == 0)
461 {
462 if (texture != 0)
463 {
464 mTextureMap[texture] = new Texture2D();
465 }
466 else // Special case: 0 refers to different initial textures based on the target
467 {
468 mTextureMap[0] = mTexture2DZero;
469 }
470 }
471
472 texture2D = texture;
473
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000474 samplerTexture[SAMPLER_2D][activeSampler] = texture;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000475}
476
477void Context::bindTextureCubeMap(GLuint texture)
478{
479 if (!getTexture(texture) || texture == 0)
480 {
481 if (texture != 0)
482 {
483 mTextureMap[texture] = new TextureCubeMap();
484 }
485 else // Special case: 0 refers to different initial textures based on the target
486 {
487 mTextureMap[0] = mTextureCubeMapZero;
488 }
489 }
490
491 textureCubeMap = texture;
492
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000493 samplerTexture[SAMPLER_CUBE][activeSampler] = texture;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000494}
495
496void Context::bindFramebuffer(GLuint framebuffer)
497{
498 if (!getFramebuffer(framebuffer))
499 {
500 mFramebufferMap[framebuffer] = new Framebuffer();
501 }
502
503 this->framebuffer = framebuffer;
504}
505
506void Context::bindRenderbuffer(GLuint renderbuffer)
507{
508 if (renderbuffer != 0 && !getRenderbuffer(renderbuffer))
509 {
510 mRenderbufferMap[renderbuffer] = new Renderbuffer();
511 }
512
513 this->renderbuffer = renderbuffer;
514}
515
516void Context::useProgram(GLuint program)
517{
518 Program *programObject = getCurrentProgram();
519
520 if (programObject && programObject->isFlaggedForDeletion())
521 {
522 deleteProgram(currentProgram);
523 }
524
525 currentProgram = program;
526}
527
528void Context::setFramebufferZero(Framebuffer *buffer)
529{
530 delete mFramebufferMap[0];
531 mFramebufferMap[0] = buffer;
532}
533
534void Context::setColorbufferZero(Colorbuffer *buffer)
535{
536 delete mColorbufferZero;
537 mColorbufferZero = buffer;
538}
539
540void Context::setDepthbufferZero(Depthbuffer *buffer)
541{
542 delete mDepthbufferZero;
543 mDepthbufferZero = buffer;
544}
545
546void Context::setStencilbufferZero(Stencilbuffer *buffer)
547{
548 delete mStencilbufferZero;
549 mStencilbufferZero = buffer;
550}
551
552void Context::setRenderbuffer(Renderbuffer *buffer)
553{
554 delete mRenderbufferMap[renderbuffer];
555 mRenderbufferMap[renderbuffer] = buffer;
556}
557
558Buffer *Context::getBuffer(unsigned int handle)
559{
560 BufferMap::iterator buffer = mBufferMap.find(handle);
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000561
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000562 if (buffer == mBufferMap.end())
563 {
564 return NULL;
565 }
566 else
567 {
568 return buffer->second;
569 }
570}
571
572Shader *Context::getShader(unsigned int handle)
573{
574 ShaderMap::iterator shader = mShaderMap.find(handle);
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000575
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000576 if (shader == mShaderMap.end())
577 {
578 return NULL;
579 }
580 else
581 {
582 return shader->second;
583 }
584}
585
586Program *Context::getProgram(unsigned int handle)
587{
588 ProgramMap::iterator program = mProgramMap.find(handle);
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000589
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000590 if (program == mProgramMap.end())
591 {
592 return NULL;
593 }
594 else
595 {
596 return program->second;
597 }
598}
599
600Texture *Context::getTexture(unsigned int handle)
601{
602 TextureMap::iterator texture = mTextureMap.find(handle);
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000603
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000604 if (texture == mTextureMap.end())
605 {
606 return NULL;
607 }
608 else
609 {
610 return texture->second;
611 }
612}
613
614Framebuffer *Context::getFramebuffer(unsigned int handle)
615{
616 FramebufferMap::iterator framebuffer = mFramebufferMap.find(handle);
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000617
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000618 if (framebuffer == mFramebufferMap.end())
619 {
620 return NULL;
621 }
622 else
623 {
624 return framebuffer->second;
625 }
626}
627
628Renderbuffer *Context::getRenderbuffer(unsigned int handle)
629{
630 RenderbufferMap::iterator renderbuffer = mRenderbufferMap.find(handle);
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +0000631
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000632 if (renderbuffer == mRenderbufferMap.end())
633 {
634 return NULL;
635 }
636 else
637 {
638 return renderbuffer->second;
639 }
640}
641
642Colorbuffer *Context::getColorbuffer(GLuint handle)
643{
644 if (handle != 0)
645 {
646 Renderbuffer *renderbuffer = getRenderbuffer(handle);
647
daniel@transgaming.come2b22122010-03-11 19:22:14 +0000648 if (renderbuffer && renderbuffer->isColorbuffer())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000649 {
650 return static_cast<Colorbuffer*>(renderbuffer);
651 }
652 }
653 else // Special case: 0 refers to different initial render targets based on the attachment type
654 {
655 return mColorbufferZero;
656 }
657
658 return NULL;
659}
660
661Depthbuffer *Context::getDepthbuffer(GLuint handle)
662{
663 if (handle != 0)
664 {
665 Renderbuffer *renderbuffer = getRenderbuffer(handle);
666
daniel@transgaming.come2b22122010-03-11 19:22:14 +0000667 if (renderbuffer && renderbuffer->isDepthbuffer())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000668 {
669 return static_cast<Depthbuffer*>(renderbuffer);
670 }
671 }
672 else // Special case: 0 refers to different initial render targets based on the attachment type
673 {
674 return mDepthbufferZero;
675 }
676
677 return NULL;
678}
679
680Stencilbuffer *Context::getStencilbuffer(GLuint handle)
681{
682 if (handle != 0)
683 {
684 Renderbuffer *renderbuffer = getRenderbuffer(handle);
685
daniel@transgaming.come2b22122010-03-11 19:22:14 +0000686 if (renderbuffer && renderbuffer->isStencilbuffer())
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000687 {
688 return static_cast<Stencilbuffer*>(renderbuffer);
689 }
690 }
691 else
692 {
693 return mStencilbufferZero;
694 }
695
696 return NULL;
697}
698
699Buffer *Context::getArrayBuffer()
700{
701 return getBuffer(arrayBuffer);
702}
703
704Buffer *Context::getElementArrayBuffer()
705{
706 return getBuffer(elementArrayBuffer);
707}
708
709Program *Context::getCurrentProgram()
710{
711 return getProgram(currentProgram);
712}
713
714Texture2D *Context::getTexture2D()
715{
716 if (texture2D == 0) // Special case: 0 refers to different initial textures based on the target
717 {
718 return mTexture2DZero;
719 }
720
721 return (Texture2D*)getTexture(texture2D);
722}
723
724TextureCubeMap *Context::getTextureCubeMap()
725{
726 if (textureCubeMap == 0) // Special case: 0 refers to different initial textures based on the target
727 {
728 return mTextureCubeMapZero;
729 }
730
731 return (TextureCubeMap*)getTexture(textureCubeMap);
732}
733
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000734Texture *Context::getSamplerTexture(unsigned int sampler, SamplerType type)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000735{
daniel@transgaming.com416485f2010-03-16 06:23:23 +0000736 return getTexture(samplerTexture[type][sampler]);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000737}
738
739Framebuffer *Context::getFramebuffer()
740{
741 return getFramebuffer(framebuffer);
742}
743
744// Applies the render target surface, depth stencil surface, viewport rectangle and
745// scissor rectangle to the Direct3D 9 device
746bool Context::applyRenderTarget(bool ignoreViewport)
747{
748 IDirect3DDevice9 *device = getDevice();
749 Framebuffer *framebufferObject = getFramebuffer();
750
751 if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE)
752 {
753 return false;
754 }
755
756 IDirect3DSurface9 *renderTarget = framebufferObject->getRenderTarget();
757 IDirect3DSurface9 *depthStencil = framebufferObject->getDepthStencil();
758
759 device->SetRenderTarget(0, renderTarget);
760 device->SetDepthStencilSurface(depthStencil);
761
762 D3DVIEWPORT9 viewport;
763 D3DSURFACE_DESC desc;
764 renderTarget->GetDesc(&desc);
765
766 if (ignoreViewport)
767 {
768 viewport.X = 0;
769 viewport.Y = 0;
770 viewport.Width = desc.Width;
771 viewport.Height = desc.Height;
772 viewport.MinZ = 0.0f;
773 viewport.MaxZ = 1.0f;
774 }
775 else
776 {
daniel@transgaming.com16973022010-03-11 19:22:19 +0000777 viewport.X = std::max(viewportX, 0);
778 viewport.Y = std::max(viewportY, 0);
779 viewport.Width = std::min(viewportWidth, (int)desc.Width - (int)viewport.X);
780 viewport.Height = std::min(viewportHeight, (int)desc.Height - (int)viewport.Y);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000781 viewport.MinZ = clamp01(zNear);
782 viewport.MaxZ = clamp01(zFar);
783 }
784
785 device->SetViewport(&viewport);
786
787 if (scissorTest)
788 {
789 RECT rect = {scissorX,
790 scissorY,
791 scissorX + scissorWidth,
792 scissorY + scissorHeight};
793
794 device->SetScissorRect(&rect);
795 device->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
796 }
797 else
798 {
799 device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
800 }
801
802 if (currentProgram)
803 {
804 D3DSURFACE_DESC description;
805 renderTarget->GetDesc(&description);
806 Program *programObject = getCurrentProgram();
807
daniel@transgaming.com79b820b2010-03-16 05:48:57 +0000808 GLint halfPixelSize = programObject->getUniformLocation("gl_HalfPixelSize");
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000809 GLfloat xy[2] = {1.0f / description.Width, 1.0f / description.Height};
810 programObject->setUniform2fv(halfPixelSize, 1, (GLfloat*)&xy);
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000811
daniel@transgaming.com79b820b2010-03-16 05:48:57 +0000812 GLint window = programObject->getUniformLocation("gl_Window");
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000813 GLfloat whxy[4] = {viewportWidth / 2.0f, viewportHeight / 2.0f, (float)viewportX + viewportWidth / 2.0f, (float)viewportY + viewportHeight / 2.0f};
814 programObject->setUniform4fv(window, 1, (GLfloat*)&whxy);
815
daniel@transgaming.com79b820b2010-03-16 05:48:57 +0000816 GLint depth = programObject->getUniformLocation("gl_Depth");
daniel@transgaming.com9b5f5442010-03-16 05:43:55 +0000817 GLfloat dz[2] = {(zFar - zNear) / 2.0f, (zNear + zFar) / 2.0f};
818 programObject->setUniform2fv(depth, 1, (GLfloat*)&dz);
819
daniel@transgaming.com79b820b2010-03-16 05:48:57 +0000820 GLint near = programObject->getUniformLocation("gl_DepthRange.near");
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000821 programObject->setUniform1fv(near, 1, &zNear);
822
daniel@transgaming.com79b820b2010-03-16 05:48:57 +0000823 GLint far = programObject->getUniformLocation("gl_DepthRange.far");
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000824 programObject->setUniform1fv(far, 1, &zFar);
825
daniel@transgaming.com79b820b2010-03-16 05:48:57 +0000826 GLint diff = programObject->getUniformLocation("gl_DepthRange.diff");
daniel@transgaming.com86487c22010-03-11 19:41:43 +0000827 GLfloat zDiff = zFar - zNear;
828 programObject->setUniform1fv(diff, 1, &zDiff);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000829 }
830
831 return true;
832}
833
834// Applies the fixed-function state (culling, depth test, alpha blending, stenciling, etc) to the Direct3D 9 device
835void Context::applyState()
836{
837 IDirect3DDevice9 *device = getDevice();
daniel@transgaming.com79b820b2010-03-16 05:48:57 +0000838 Program *programObject = getCurrentProgram();
839
840 GLint frontCCW = programObject->getUniformLocation("__frontCCW");
841 GLint ccw = (frontFace == GL_CCW);
842 programObject->setUniform1iv(frontCCW, 1, &ccw);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000843
844 if (cullFace)
845 {
846 device->SetRenderState(D3DRS_CULLMODE, es2dx::ConvertCullMode(cullMode, frontFace));
847 }
848 else
849 {
850 device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
851 }
852
853 if (depthTest)
854 {
855 device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
856 device->SetRenderState(D3DRS_ZFUNC, es2dx::ConvertComparison(depthFunc));
857 }
858 else
859 {
860 device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
861 }
862
863 if (blend)
864 {
865 device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
866
867 if (sourceBlendRGB != GL_CONSTANT_ALPHA && sourceBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA &&
868 destBlendRGB != GL_CONSTANT_ALPHA && destBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA)
869 {
870 device->SetRenderState(D3DRS_BLENDFACTOR, es2dx::ConvertColor(blendColor));
871 }
872 else
873 {
874 device->SetRenderState(D3DRS_BLENDFACTOR, D3DCOLOR_RGBA(unorm<8>(blendColor.alpha),
875 unorm<8>(blendColor.alpha),
876 unorm<8>(blendColor.alpha),
877 unorm<8>(blendColor.alpha)));
878 }
879
880 device->SetRenderState(D3DRS_SRCBLEND, es2dx::ConvertBlendFunc(sourceBlendRGB));
881 device->SetRenderState(D3DRS_DESTBLEND, es2dx::ConvertBlendFunc(destBlendRGB));
882 device->SetRenderState(D3DRS_BLENDOP, es2dx::ConvertBlendOp(blendEquationRGB));
883
884 if (sourceBlendRGB != sourceBlendAlpha || destBlendRGB != destBlendAlpha || blendEquationRGB != blendEquationAlpha)
885 {
886 device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
887
888 device->SetRenderState(D3DRS_SRCBLENDALPHA, es2dx::ConvertBlendFunc(sourceBlendAlpha));
889 device->SetRenderState(D3DRS_DESTBLENDALPHA, es2dx::ConvertBlendFunc(destBlendAlpha));
890 device->SetRenderState(D3DRS_BLENDOPALPHA, es2dx::ConvertBlendOp(blendEquationAlpha));
891
892 }
893 else
894 {
895 device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
896 }
897 }
898 else
899 {
900 device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
901 }
902
903 if (stencilTest)
904 {
905 device->SetRenderState(D3DRS_STENCILENABLE, TRUE);
906 device->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE);
907
908 // FIXME: Unsupported by D3D9
909 const D3DRENDERSTATETYPE D3DRS_CCW_STENCILREF = D3DRS_STENCILREF;
910 const D3DRENDERSTATETYPE D3DRS_CCW_STENCILMASK = D3DRS_STENCILMASK;
911 const D3DRENDERSTATETYPE D3DRS_CCW_STENCILWRITEMASK = D3DRS_STENCILWRITEMASK;
912 ASSERT(stencilRef == stencilBackRef);
913 ASSERT(stencilMask == stencilBackMask);
914 ASSERT(stencilWritemask == stencilBackWritemask);
915
916 device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, stencilWritemask);
917 device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, es2dx::ConvertComparison(stencilFunc));
918
919 device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, stencilRef); // FIXME: Clamp to range
920 device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, stencilMask);
921
922 device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, es2dx::ConvertStencilOp(stencilFail));
923 device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, es2dx::ConvertStencilOp(stencilPassDepthFail));
924 device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, es2dx::ConvertStencilOp(stencilPassDepthPass));
925
926 device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, stencilBackWritemask);
927 device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, es2dx::ConvertComparison(stencilBackFunc));
928
929 device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, stencilBackRef); // FIXME: Clamp to range
930 device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, stencilBackMask);
931
932 device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, es2dx::ConvertStencilOp(stencilBackFail));
933 device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, es2dx::ConvertStencilOp(stencilBackPassDepthFail));
934 device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, es2dx::ConvertStencilOp(stencilBackPassDepthPass));
935 }
936 else
937 {
938 device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
939 }
940
941 device->SetRenderState(D3DRS_COLORWRITEENABLE, es2dx::ConvertColorMask(colorMaskRed, colorMaskGreen, colorMaskBlue, colorMaskAlpha));
942 device->SetRenderState(D3DRS_ZWRITEENABLE, depthMask ? TRUE : FALSE);
943
944 if (polygonOffsetFill)
945 {
946 UNIMPLEMENTED(); // FIXME
947 }
948
949 if (sampleAlphaToCoverage)
950 {
951 UNIMPLEMENTED(); // FIXME
952 }
953
954 if (sampleCoverage)
955 {
956 UNIMPLEMENTED(); // FIXME: Ignore when SAMPLE_BUFFERS is not one
957 }
958
959 device->SetRenderState(D3DRS_DITHERENABLE, dither ? TRUE : FALSE);
960}
961
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000962// Fill in the programAttribute field of the array of TranslatedAttributes based on the active GLSL program.
963void Context::lookupAttributeMapping(TranslatedAttribute *attributes)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000964{
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000965 for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000966 {
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000967 if (attributes[i].enabled)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000968 {
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000969 attributes[i].programAttribute = getCurrentProgram()->getInputMapping(i);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000970 }
971 }
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000972}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000973
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000974// The indices parameter to glDrawElements can have two interpretations:
975// - as a pointer into client memory
976// - as an offset into the current GL_ELEMENT_ARRAY_BUFFER buffer
977// Handle these cases here and return a pointer to the index data.
978const Index *Context::adjustIndexPointer(const void *indices)
979{
980 if (elementArrayBuffer)
981 {
982 Buffer *buffer = getBuffer(elementArrayBuffer);
983 return reinterpret_cast<const Index*>(static_cast<unsigned char*>(buffer->data()) + reinterpret_cast<GLsizei>(indices));
984 }
985 else
986 {
987 return static_cast<const Index*>(indices);
988 }
989}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +0000990
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +0000991void Context::applyVertexBuffer(GLint first, GLsizei count)
992{
993 TranslatedAttribute translated[MAX_VERTEX_ATTRIBS];
994
995 mVertexDataManager->preRenderValidate(first, count, translated);
996
997 lookupAttributeMapping(translated);
998
999 mBufferBackEnd->preDraw(translated);
1000}
1001
1002void Context::applyVertexBuffer(GLsizei count, const void *indices, GLenum indexType)
1003{
1004 TranslatedAttribute translated[MAX_VERTEX_ATTRIBS];
1005
1006 mVertexDataManager->preRenderValidate(adjustIndexPointer(indices), count, translated);
1007
1008 lookupAttributeMapping(translated);
1009
1010 mBufferBackEnd->preDraw(translated);
1011}
1012
1013// Applies the indices and element array bindings to the Direct3D 9 device
1014void Context::applyIndexBuffer(const void *indices, GLsizei count)
1015{
1016 GLsizei length = count * sizeof(Index);
1017
1018 IDirect3DDevice9 *device = getDevice();
1019
1020 IDirect3DIndexBuffer9 *indexBuffer = NULL;
1021 void *data;
1022
1023 HRESULT result = device->CreateIndexBuffer(length, 0, D3DFMT_INDEX16, D3DPOOL_MANAGED, &indexBuffer, NULL);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001024
1025 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
1026 {
1027 return error(GL_OUT_OF_MEMORY);
1028 }
1029
1030 ASSERT(SUCCEEDED(result));
1031
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +00001032 if (indexBuffer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001033 {
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +00001034 indexBuffer->Lock(0, length, &data, 0);
1035 memcpy(data, adjustIndexPointer(indices), length);
1036 indexBuffer->Unlock();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001037
1038 device->SetIndices(indexBuffer);
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +00001039 indexBuffer->Release(); // Will only effectively be deleted when no longer in use
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001040 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001041
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +00001042 startIndex = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001043}
1044
1045// Applies the shaders and shader constants to the Direct3D 9 device
1046void Context::applyShaders()
1047{
1048 IDirect3DDevice9 *device = getDevice();
1049 Program *programObject = getCurrentProgram();
1050 IDirect3DVertexShader9 *vertexShader = programObject->getVertexShader();
1051 IDirect3DPixelShader9 *pixelShader = programObject->getPixelShader();
1052
1053 device->SetVertexShader(vertexShader);
1054 device->SetPixelShader(pixelShader);
1055
1056 programObject->applyUniforms();
1057}
1058
1059// Applies the textures and sampler states to the Direct3D 9 device
1060void Context::applyTextures()
1061{
1062 IDirect3DDevice9 *device = getDevice();
1063 Program *programObject = getCurrentProgram();
1064
1065 for (int sampler = 0; sampler < MAX_TEXTURE_IMAGE_UNITS; sampler++)
1066 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001067 int textureUnit = programObject->getSamplerMapping(sampler);
1068 if (textureUnit != -1)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001069 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001070 SamplerType textureType = programObject->getSamplerType(sampler);
1071
1072 Texture *texture = getSamplerTexture(textureUnit, textureType);
1073
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001074 if (texture->isComplete())
1075 {
1076 GLenum wrapS = texture->getWrapS();
1077 GLenum wrapT = texture->getWrapT();
1078 GLenum minFilter = texture->getMinFilter();
1079 GLenum magFilter = texture->getMagFilter();
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001080
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001081 device->SetSamplerState(sampler, D3DSAMP_ADDRESSU, es2dx::ConvertTextureWrap(wrapS));
1082 device->SetSamplerState(sampler, D3DSAMP_ADDRESSV, es2dx::ConvertTextureWrap(wrapT));
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001083
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001084 device->SetSamplerState(sampler, D3DSAMP_MAGFILTER, es2dx::ConvertMagFilter(magFilter));
1085 D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter;
1086 es2dx::ConvertMinFilter(minFilter, &d3dMinFilter, &d3dMipFilter);
1087 device->SetSamplerState(sampler, D3DSAMP_MINFILTER, d3dMinFilter);
1088 device->SetSamplerState(sampler, D3DSAMP_MIPFILTER, d3dMipFilter);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001089
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001090 device->SetTexture(sampler, texture->getTexture());
1091 }
1092 else
1093 {
1094 device->SetTexture(sampler, getIncompleteTexture(textureType)->getTexture());
1095 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001096 }
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001097 else
1098 {
1099 device->SetTexture(sampler, NULL);
1100 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001101 }
1102}
1103
1104void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels)
1105{
1106 Framebuffer *framebuffer = getFramebuffer();
1107 IDirect3DSurface9 *renderTarget = framebuffer->getRenderTarget();
1108 IDirect3DDevice9 *device = getDevice();
1109
1110 D3DSURFACE_DESC desc;
1111 renderTarget->GetDesc(&desc);
1112
1113 IDirect3DSurface9 *systemSurface;
1114 HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &systemSurface, NULL);
1115
1116 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
1117 {
1118 return error(GL_OUT_OF_MEMORY);
1119 }
1120
1121 ASSERT(SUCCEEDED(result));
1122
1123 if (desc.MultiSampleType != D3DMULTISAMPLE_NONE)
1124 {
1125 UNIMPLEMENTED(); // FIXME: Requires resolve using StretchRect into non-multisampled render target
1126 }
1127
1128 result = device->GetRenderTargetData(renderTarget, systemSurface);
1129
1130 if (result == D3DERR_DRIVERINTERNALERROR)
1131 {
1132 systemSurface->Release();
1133
1134 return error(GL_OUT_OF_MEMORY);
1135 }
1136
1137 if (FAILED(result))
1138 {
1139 UNREACHABLE();
1140 systemSurface->Release();
1141
1142 return; // No sensible error to generate
1143 }
1144
1145 D3DLOCKED_RECT lock;
daniel@transgaming.com16973022010-03-11 19:22:19 +00001146 RECT rect = {std::max(x, 0),
1147 std::max(y, 0),
1148 std::min(x + width, (int)desc.Width),
1149 std::min(y + height, (int)desc.Height)};
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001150
1151 result = systemSurface->LockRect(&lock, &rect, D3DLOCK_READONLY);
1152
1153 if (FAILED(result))
1154 {
1155 UNREACHABLE();
1156 systemSurface->Release();
1157
1158 return; // No sensible error to generate
1159 }
1160
1161 unsigned char *source = (unsigned char*)lock.pBits;
1162 unsigned char *dest = (unsigned char*)pixels;
1163
1164 for (int j = 0; j < rect.bottom - rect.top; j++)
1165 {
1166 for (int i = 0; i < rect.right - rect.left; i++)
1167 {
1168 float r;
1169 float g;
1170 float b;
1171 float a;
1172
1173 switch (desc.Format)
1174 {
1175 case D3DFMT_R5G6B5:
1176 {
1177 unsigned short rgb = *(unsigned short*)(source + 2 * i + j * lock.Pitch);
1178
1179 a = 1.0f;
1180 b = (rgb & 0x001F) * (1.0f / 0x001F);
1181 g = (rgb & 0x07E0) * (1.0f / 0x07E0);
1182 r = (rgb & 0xF800) * (1.0f / 0xF800);
1183 }
1184 break;
1185 case D3DFMT_X1R5G5B5:
1186 {
1187 unsigned short xrgb = *(unsigned short*)(source + 2 * i + j * lock.Pitch);
1188
1189 a = 1.0f;
1190 b = (xrgb & 0x001F) * (1.0f / 0x001F);
1191 g = (xrgb & 0x03E0) * (1.0f / 0x03E0);
1192 r = (xrgb & 0x7C00) * (1.0f / 0x7C00);
1193 }
1194 break;
1195 case D3DFMT_A1R5G5B5:
1196 {
1197 unsigned short argb = *(unsigned short*)(source + 2 * i + j * lock.Pitch);
1198
1199 a = (argb & 0x8000) ? 1.0f : 0.0f;
1200 b = (argb & 0x001F) * (1.0f / 0x001F);
1201 g = (argb & 0x03E0) * (1.0f / 0x03E0);
1202 r = (argb & 0x7C00) * (1.0f / 0x7C00);
1203 }
1204 break;
1205 case D3DFMT_A8R8G8B8:
1206 {
1207 unsigned int argb = *(unsigned int*)(source + 4 * i + j * lock.Pitch);
1208
1209 a = (argb & 0xFF000000) * (1.0f / 0xFF000000);
1210 b = (argb & 0x000000FF) * (1.0f / 0x000000FF);
1211 g = (argb & 0x0000FF00) * (1.0f / 0x0000FF00);
1212 r = (argb & 0x00FF0000) * (1.0f / 0x00FF0000);
1213 }
1214 break;
1215 case D3DFMT_X8R8G8B8:
1216 {
1217 unsigned int xrgb = *(unsigned int*)(source + 4 * i + j * lock.Pitch);
1218
1219 a = 1.0f;
1220 b = (xrgb & 0x000000FF) * (1.0f / 0x000000FF);
1221 g = (xrgb & 0x0000FF00) * (1.0f / 0x0000FF00);
1222 r = (xrgb & 0x00FF0000) * (1.0f / 0x00FF0000);
1223 }
1224 break;
1225 case D3DFMT_A2R10G10B10:
1226 {
1227 unsigned int argb = *(unsigned int*)(source + 4 * i + j * lock.Pitch);
1228
1229 a = (argb & 0xC0000000) * (1.0f / 0xC0000000);
1230 b = (argb & 0x000003FF) * (1.0f / 0x000003FF);
1231 g = (argb & 0x000FFC00) * (1.0f / 0x000FFC00);
1232 r = (argb & 0x3FF00000) * (1.0f / 0x3FF00000);
1233 }
1234 break;
1235 default:
1236 UNIMPLEMENTED(); // FIXME
1237 UNREACHABLE();
1238 }
1239
1240 switch (format)
1241 {
1242 case GL_RGBA:
1243 switch (type)
1244 {
1245 case GL_UNSIGNED_BYTE:
1246 dest[4 * (i + j * width) + 0] = (unsigned char)(255 * r + 0.5f);
1247 dest[4 * (i + j * width) + 1] = (unsigned char)(255 * g + 0.5f);
1248 dest[4 * (i + j * width) + 2] = (unsigned char)(255 * b + 0.5f);
1249 dest[4 * (i + j * width) + 3] = (unsigned char)(255 * a + 0.5f);
1250 break;
1251 default: UNREACHABLE();
1252 }
1253 break;
1254 case IMPLEMENTATION_COLOR_READ_FORMAT:
1255 switch (type)
1256 {
1257 case IMPLEMENTATION_COLOR_READ_TYPE:
1258 break;
1259 default: UNREACHABLE();
1260 }
1261 break;
1262 default: UNREACHABLE();
1263 }
1264 }
1265 }
1266
1267 systemSurface->UnlockRect();
1268
1269 systemSurface->Release();
1270}
1271
1272void Context::clear(GLbitfield mask)
1273{
1274 IDirect3DDevice9 *device = getDevice();
1275 DWORD flags = 0;
1276
1277 if (mask & GL_COLOR_BUFFER_BIT)
1278 {
1279 mask &= ~GL_COLOR_BUFFER_BIT;
1280 flags |= D3DCLEAR_TARGET;
1281 }
1282
1283 if (mask & GL_DEPTH_BUFFER_BIT)
1284 {
1285 mask &= ~GL_DEPTH_BUFFER_BIT;
1286 if (depthMask)
1287 {
1288 flags |= D3DCLEAR_ZBUFFER;
1289 }
1290 }
1291
1292 Framebuffer *framebufferObject = getFramebuffer();
1293 IDirect3DSurface9 *depthStencil = framebufferObject->getDepthStencil();
1294
1295 GLuint stencilUnmasked = 0x0;
1296
1297 if ((mask & GL_STENCIL_BUFFER_BIT) && depthStencil)
1298 {
1299 D3DSURFACE_DESC desc;
1300 depthStencil->GetDesc(&desc);
1301
1302 mask &= ~GL_STENCIL_BUFFER_BIT;
1303 unsigned int stencilSize = es2dx::GetStencilSize(desc.Format);
1304 stencilUnmasked = (0x1 << stencilSize) - 1;
1305
1306 if (stencilUnmasked != 0x0)
1307 {
1308 flags |= D3DCLEAR_STENCIL;
1309 }
1310 }
1311
1312 if (mask != 0)
1313 {
1314 return error(GL_INVALID_VALUE);
1315 }
1316
1317 applyRenderTarget(true); // Clips the clear to the scissor rectangle but not the viewport
1318
1319 D3DCOLOR color = D3DCOLOR_ARGB(unorm<8>(colorClearValue.alpha), unorm<8>(colorClearValue.red), unorm<8>(colorClearValue.green), unorm<8>(colorClearValue.blue));
1320 float depth = clamp01(depthClearValue);
1321 int stencil = stencilClearValue & 0x000000FF;
1322
1323 IDirect3DSurface9 *renderTarget = framebufferObject->getRenderTarget();
1324
1325 D3DSURFACE_DESC desc;
1326 renderTarget->GetDesc(&desc);
1327
1328 bool alphaUnmasked = (es2dx::GetAlphaSize(desc.Format) == 0) || colorMaskAlpha;
1329
1330 const bool needMaskedStencilClear = (flags & D3DCLEAR_STENCIL) &&
1331 (stencilWritemask & stencilUnmasked) != stencilUnmasked;
1332 const bool needMaskedColorClear = (flags & D3DCLEAR_TARGET) &&
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001333 !(colorMaskRed && colorMaskGreen &&
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001334 colorMaskBlue && alphaUnmasked);
1335
1336 if (needMaskedColorClear || needMaskedStencilClear)
1337 {
1338 device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
1339 device->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
1340 device->SetRenderState(D3DRS_ZENABLE, FALSE);
1341 device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
1342 device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
1343 device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
1344 device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
1345 device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
1346
1347 if (flags & D3DCLEAR_TARGET)
1348 {
1349 device->SetRenderState(D3DRS_COLORWRITEENABLE, (colorMaskRed ? D3DCOLORWRITEENABLE_RED : 0) |
1350 (colorMaskGreen ? D3DCOLORWRITEENABLE_GREEN : 0) |
1351 (colorMaskBlue ? D3DCOLORWRITEENABLE_BLUE : 0) |
1352 (colorMaskAlpha ? D3DCOLORWRITEENABLE_ALPHA : 0));
1353 }
1354 else
1355 {
1356 device->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
1357 }
1358
1359 if (stencilUnmasked != 0x0 && (flags & D3DCLEAR_STENCIL))
1360 {
1361 device->SetRenderState(D3DRS_STENCILENABLE, TRUE);
1362 device->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
1363 device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);
1364 device->SetRenderState(D3DRS_STENCILREF, stencil);
1365 device->SetRenderState(D3DRS_STENCILWRITEMASK, stencilWritemask);
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001366 device->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001367 device->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_REPLACE);
1368 device->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE);
1369 }
1370 else
1371 {
1372 device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
1373 }
1374
1375 device->SetPixelShader(NULL);
1376 device->SetVertexShader(NULL);
1377 device->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
1378
daniel@transgaming.comfab5a1a2010-03-11 19:22:30 +00001379 struct Vertex
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001380 {
1381 float x, y, z, w;
1382 D3DCOLOR diffuse;
1383 };
1384
1385 Vertex quad[4];
1386 quad[0].x = 0.0f;
1387 quad[0].y = (float)desc.Height;
1388 quad[0].z = 0.0f;
1389 quad[0].w = 1.0f;
1390 quad[0].diffuse = color;
1391
1392 quad[1].x = (float)desc.Width;
1393 quad[1].y = (float)desc.Height;
1394 quad[1].z = 0.0f;
1395 quad[1].w = 1.0f;
1396 quad[1].diffuse = color;
1397
1398 quad[2].x = 0.0f;
1399 quad[2].y = 0.0f;
1400 quad[2].z = 0.0f;
1401 quad[2].w = 1.0f;
1402 quad[2].diffuse = color;
1403
1404 quad[3].x = (float)desc.Width;
1405 quad[3].y = 0.0f;
1406 quad[3].z = 0.0f;
1407 quad[3].w = 1.0f;
1408 quad[3].diffuse = color;
1409
1410 device->BeginScene();
1411 device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(Vertex));
1412 device->EndScene();
1413
1414 if (flags & D3DCLEAR_ZBUFFER)
1415 {
1416 device->SetRenderState(D3DRS_ZENABLE, TRUE);
1417 device->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
1418 device->Clear(0, NULL, D3DCLEAR_ZBUFFER, color, depth, stencil);
1419 }
1420 }
1421 else
1422 {
1423 device->Clear(0, NULL, flags, color, depth, stencil);
1424 }
1425}
1426
1427void Context::drawArrays(GLenum mode, GLint first, GLsizei count)
1428{
1429 if (!currentProgram)
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(first, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001453 applyShaders();
1454 applyTextures();
1455
1456 device->BeginScene();
1457 device->DrawPrimitive(primitiveType, first, primitiveCount);
1458 device->EndScene();
1459}
1460
1461void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const void* indices)
1462{
1463 if (!currentProgram)
1464 {
1465 return error(GL_INVALID_OPERATION);
1466 }
1467
1468 if (!indices && !elementArrayBuffer)
1469 {
1470 return error(GL_INVALID_OPERATION);
1471 }
1472
1473 IDirect3DDevice9 *device = getDevice();
1474 D3DPRIMITIVETYPE primitiveType;
1475 int primitiveCount;
1476
1477 if(!es2dx::ConvertPrimitiveType(mode, count, &primitiveType, &primitiveCount))
1478 return error(GL_INVALID_ENUM);
1479
1480 if (primitiveCount <= 0)
1481 {
1482 return;
1483 }
1484
1485 if (!applyRenderTarget(false))
1486 {
1487 return error(GL_INVALID_FRAMEBUFFER_OPERATION);
1488 }
1489
1490 applyState();
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +00001491 applyVertexBuffer(count, indices, type);
1492 applyIndexBuffer(indices, count);
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001493 applyShaders();
1494 applyTextures();
1495
1496 device->BeginScene();
1497 device->DrawIndexedPrimitive(primitiveType, 0, 0, count, startIndex, primitiveCount);
1498 device->EndScene();
1499}
1500
1501void Context::finish()
1502{
1503 IDirect3DDevice9 *device = getDevice();
1504 IDirect3DQuery9 *occlusionQuery = NULL;
1505
1506 HRESULT result = device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery);
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 (occlusionQuery)
1516 {
1517 occlusionQuery->Issue(D3DISSUE_BEGIN);
1518
1519 // Render something outside the render target
1520 device->SetPixelShader(NULL);
1521 device->SetVertexShader(NULL);
1522 device->SetFVF(D3DFVF_XYZRHW);
1523 float data[4] = {-1.0f, -1.0f, -1.0f, 1.0f};
1524 device->BeginScene();
1525 device->DrawPrimitiveUP(D3DPT_POINTLIST, 1, data, sizeof(data));
1526 device->EndScene();
1527
1528 occlusionQuery->Issue(D3DISSUE_END);
1529
1530 while (occlusionQuery->GetData(NULL, 0, D3DGETDATA_FLUSH) == S_FALSE)
1531 {
1532 // Keep polling, but allow other threads to do something useful first
1533 Sleep(0);
1534 }
1535
1536 occlusionQuery->Release();
1537 }
1538}
1539
1540void Context::flush()
1541{
1542 IDirect3DDevice9 *device = getDevice();
1543 IDirect3DQuery9 *eventQuery = NULL;
1544
1545 HRESULT result = device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery);
1546
1547 if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
1548 {
1549 return error(GL_OUT_OF_MEMORY);
1550 }
1551
1552 ASSERT(SUCCEEDED(result));
1553
1554 if (eventQuery)
1555 {
1556 eventQuery->Issue(D3DISSUE_END);
1557
1558 while (eventQuery->GetData(NULL, 0, D3DGETDATA_FLUSH) == S_FALSE)
1559 {
1560 // Keep polling, but allow other threads to do something useful first
1561 Sleep(0);
1562 }
1563
1564 eventQuery->Release();
1565 }
1566}
1567
1568void Context::recordInvalidEnum()
1569{
1570 mInvalidEnum = true;
1571}
1572
1573void Context::recordInvalidValue()
1574{
1575 mInvalidValue = true;
1576}
1577
1578void Context::recordInvalidOperation()
1579{
1580 mInvalidOperation = true;
1581}
1582
1583void Context::recordOutOfMemory()
1584{
1585 mOutOfMemory = true;
1586}
1587
1588void Context::recordInvalidFramebufferOperation()
1589{
1590 mInvalidFramebufferOperation = true;
1591}
1592
1593// Get one of the recorded errors and clear its flag, if any.
1594// [OpenGL ES 2.0.24] section 2.5 page 13.
1595GLenum Context::getError()
1596{
1597 if (mInvalidEnum)
1598 {
1599 mInvalidEnum = false;
1600
1601 return GL_INVALID_ENUM;
1602 }
1603
1604 if (mInvalidValue)
1605 {
1606 mInvalidValue = false;
1607
1608 return GL_INVALID_VALUE;
1609 }
1610
1611 if (mInvalidOperation)
1612 {
1613 mInvalidOperation = false;
1614
1615 return GL_INVALID_OPERATION;
1616 }
1617
1618 if (mOutOfMemory)
1619 {
1620 mOutOfMemory = false;
1621
1622 return GL_OUT_OF_MEMORY;
1623 }
1624
1625 if (mInvalidFramebufferOperation)
1626 {
1627 mInvalidFramebufferOperation = false;
1628
1629 return GL_INVALID_FRAMEBUFFER_OPERATION;
1630 }
1631
1632 return GL_NO_ERROR;
1633}
1634
1635void Context::detachBuffer(GLuint buffer)
1636{
1637 // [OpenGL ES 2.0.24] section 2.9 page 22:
1638 // If a buffer object is deleted while it is bound, all bindings to that object in the current context
1639 // (i.e. in the thread that called Delete-Buffers) are reset to zero.
1640
1641 if (arrayBuffer == buffer)
1642 {
1643 arrayBuffer = 0;
1644 }
1645
1646 if (elementArrayBuffer == buffer)
1647 {
1648 elementArrayBuffer = 0;
1649 }
1650
1651 for (int attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
1652 {
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +00001653 if (vertexAttribute[attribute].mBoundBuffer == buffer)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001654 {
daniel@transgaming.com0f7aaf52010-03-11 19:41:38 +00001655 vertexAttribute[attribute].mBoundBuffer = 0;
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001656 }
1657 }
1658}
1659
1660void Context::detachTexture(GLuint texture)
1661{
1662 // [OpenGL ES 2.0.24] section 3.8 page 84:
1663 // If a texture object is deleted, it is as if all texture units which are bound to that texture object are
1664 // rebound to texture object zero
1665
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001666 for (int type = 0; type < SAMPLER_TYPE_COUNT; type++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001667 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001668 for (int sampler = 0; sampler < MAX_TEXTURE_IMAGE_UNITS; sampler++)
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001669 {
daniel@transgaming.com416485f2010-03-16 06:23:23 +00001670 if (samplerTexture[type][sampler] == texture)
1671 {
1672 samplerTexture[type][sampler] = 0;
1673 }
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001674 }
1675 }
1676
1677 // [OpenGL ES 2.0.24] section 4.4 page 112:
1678 // If a texture object is deleted while its image is attached to the currently bound framebuffer, then it is
1679 // as if FramebufferTexture2D had been called, with a texture of 0, for each attachment point to which this
1680 // image was attached in the currently bound framebuffer.
1681
1682 Framebuffer *framebuffer = getFramebuffer();
1683
1684 if (framebuffer)
1685 {
1686 framebuffer->detachTexture(texture);
1687 }
1688}
1689
1690void Context::detachFramebuffer(GLuint framebuffer)
1691{
1692 // [OpenGL ES 2.0.24] section 4.4 page 107:
1693 // If a framebuffer that is currently bound to the target FRAMEBUFFER is deleted, it is as though
1694 // BindFramebuffer had been executed with the target of FRAMEBUFFER and framebuffer of zero.
1695
1696 if (this->framebuffer == framebuffer)
1697 {
1698 bindFramebuffer(0);
1699 }
1700}
1701
1702void Context::detachRenderbuffer(GLuint renderbuffer)
1703{
1704 // [OpenGL ES 2.0.24] section 4.4 page 109:
1705 // If a renderbuffer that is currently bound to RENDERBUFFER is deleted, it is as though BindRenderbuffer
1706 // had been executed with the target RENDERBUFFER and name of zero.
1707
1708 if (this->renderbuffer == renderbuffer)
1709 {
1710 bindRenderbuffer(0);
1711 }
1712
1713 // [OpenGL ES 2.0.24] section 4.4 page 111:
1714 // If a renderbuffer object is deleted while its image is attached to the currently bound framebuffer,
1715 // then it is as if FramebufferRenderbuffer had been called, with a renderbuffer of 0, for each attachment
1716 // point to which this image was attached in the currently bound framebuffer.
1717
1718 Framebuffer *framebuffer = getFramebuffer();
1719
1720 if (framebuffer)
1721 {
1722 framebuffer->detachRenderbuffer(renderbuffer);
1723 }
1724}
daniel@transgaming.com12d54072010-03-16 06:23:26 +00001725
1726Texture *Context::getIncompleteTexture(SamplerType type)
1727{
1728 Texture *t = mIncompleteTextures[type];
1729
1730 if (t == NULL)
1731 {
1732 static const GLubyte color[] = { 0, 0, 0, 255 };
1733
1734 switch (type)
1735 {
1736 default:
1737 UNREACHABLE();
1738 // default falls through to SAMPLER_2D
1739
1740 case SAMPLER_2D:
1741 {
1742 Texture2D *incomplete2d = new Texture2D;
1743 incomplete2d->setImage(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, color);
1744 t = incomplete2d;
1745 }
1746 break;
1747
1748 case SAMPLER_CUBE:
1749 {
1750 TextureCubeMap *incompleteCube = new TextureCubeMap;
1751
1752 incompleteCube->setImagePosX(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, color);
1753 incompleteCube->setImageNegX(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, color);
1754 incompleteCube->setImagePosY(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, color);
1755 incompleteCube->setImageNegY(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, color);
1756 incompleteCube->setImagePosZ(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, color);
1757 incompleteCube->setImageNegZ(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, color);
1758
1759 t = incompleteCube;
1760 }
1761 break;
1762 }
1763
1764 mIncompleteTextures[type] = t;
1765 }
1766
1767 return t;
1768}
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001769}
1770
1771extern "C"
1772{
1773gl::Context *glCreateContext(const egl::Config *config)
1774{
1775 return new gl::Context(config);
1776}
1777
1778void glDestroyContext(gl::Context *context)
1779{
1780 delete context;
1781
1782 if (context == gl::getContext())
1783 {
1784 gl::makeCurrent(NULL, NULL, NULL);
1785 }
1786}
1787
1788void glMakeCurrent(gl::Context *context, egl::Display *display, egl::Surface *surface)
1789{
1790 gl::makeCurrent(context, display, surface);
1791}
1792
1793gl::Context *glGetCurrentContext()
1794{
1795 return gl::getContext();
1796}
1797}