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