summaryrefslogtreecommitdiffstats
path: root/Source/ThirdParty/ANGLE/src/libGLESv2/Context.cpp
diff options
context:
space:
mode:
authorPierre-Antoine LaFayette <plafayet@codeaurora.org>2011-12-29 15:13:33 +0100
committerSteve Kondik <shade@chemlab.org>2013-01-20 18:38:26 -0800
commit70f026a42cf1bee061389fa6ce790ea1186f0703 (patch)
treeb0de5b5676433d2382e7cf1307b54edc19fc42a5 /Source/ThirdParty/ANGLE/src/libGLESv2/Context.cpp
parenta815c626d7df7e24ba9e0df27c27735d4e069ffd (diff)
downloadexternal_webkit-70f026a42cf1bee061389fa6ce790ea1186f0703.zip
external_webkit-70f026a42cf1bee061389fa6ce790ea1186f0703.tar.gz
external_webkit-70f026a42cf1bee061389fa6ce790ea1186f0703.tar.bz2
WebGL implementation for Android
Implementation of WebGL in Android WebKit. Exposes a low level 3D graphics API based on OpenGL ES 2.0 to JavaScript. WebGL is not compiled by default. It can be enabled by setting ENABLE_WEBGL = true in your device BoardConfig.mk or directly in external/webkit/Android.mk. Includes runtime enablement through Browser Settings -> Labs menu. Enable WebGL debug logs and FPS timing with: adb shell setprop debug.webgl 1 Includes Cross-origin resource sharing support. Includes fixes for the following Khronos WebGL 1.0.1. tests: - premultiplyalpha-test.html - struct-nesting-exceeds-maximum.html - index-validation.html - context-attributes-alpha-depth-stencil-antialias.html - program-test.html - object-deletion-behaviour.html Squashed patches: ----------------------------------------------------------- WebGL implementation for Android Implementation of WebGL in Android WebKit. Exposes a low level 3D graphics API based on OpenGL ES 2.0 to JavaScript. WebGL is not compiled by default. It can be enabled by setting ENABLE_WEBGL = true in your device BoardConfig.mk or directly in external/webkit/Android.mk. It is also disabled by default (in WebSettings.cpp) as required by Khronos until it reaches 100% conformance. -- From: Anders Edenbrandt <anders.edenbrandt@sonyericsson.com> Date: Thu, 26 Jan 2012 11:48:41 +0100 WebGL bug fixes and updates Some updates: - stability fixes - image decoder - redesign of how the FBOs are used - other bug fixes -- From: Anders Edenbrandt <anders.edenbrandt@sonyericsson.com> Date: Tue, 31 Jan 2012 17:20:13 +0100 WebGL code cleanup and bug fixes -- From: Anders Edenbrandt <anders.edenbrandt@sonyericsson.com> Date: Thu Mar 15 10:15:33 2012 +0100 More improvements and bug fixes Updates: - cleaned up buffer handling, allowing for arbitrary number of buffers - removed rect from invalidation - removed screen update request from drawGL - releasing buffers when the browser is paused - added missing method 'slice' for typed arrays - fixed bug in bindFramebuffer https://www.codeaurora.org/gitweb/quic/la/?p=platform/external/webkit.git;a=commit;h=c72ff2aa562941d94ceb51ba685d60809ca882a6 Updates to fix some test failures in Khronos Conformance Test Suite: - Increase max identifier length in shaders to 256 - Add length check on uniforms and attributes - Add minimal support for compressed textures (that is, just return the correct error codes) - Add support for Uint8ClampedByteArray - Modify how error checking is done on framebuffer operations - Activate the GL_OES_packed_depth_stencil extension - Activate the GL_OES_texture_float extension https://www.codeaurora.org/gitweb/quic/la/?p=platform/external/webkit.git;a=commit;h=5bfe05848c12a2894697fbb503cfa79981eb96bd Fix WebGL 1.0.1 premultiplyalpha-test conformance test Fixing bug with toDataURL when called against a Canvas in which WebGL content is being rendered and make sure paintRenderingResultsToImageData isn't used for the premultiplied case. ihttps://www.codeaurora.org/gitweb/quic/la/?p=platform/external/webkit.git;a=commit;h=5834a1e00f89d898a7a0039d47916b196e40a2c8 Update ANGLE to r1009 to fix WebGL 1.0.1 conformance test Fixes struct-nesting-exceeds-maximum Khronos WebGL conformance test. https://www.codeaurora.org/gitweb/quic/la/?p=platform/external/webkit.git;a=commit;h=ae2392db6360b41a5717f3770a9e63b1bcea45d6 vertexAttribPointer needs to reject large negative offsets https://bugs.webkit.org/show_bug.cgi?id=85117 Reviewed by Kenneth Russell. Source/WebCore: * html/canvas/WebGLRenderingContext.cpp: Use long long for GLsizeiptr and GLintptr (WebCore): (WebCore::WebGLRenderingContext::bufferData): (WebCore::WebGLRenderingContext::bufferSubData): (WebCore::WebGLRenderingContext::drawElements): (WebCore::WebGLRenderingContext::getVertexAttribOffset): (WebCore::WebGLRenderingContext::vertexAttribPointer): * html/canvas/WebGLRenderingContext.h: Ditto (WebGLRenderingContext): * html/canvas/WebGLRenderingContext.idl: Ditto LayoutTests: * fast/canvas/webgl/index-validation-expected.txt: * fast/canvas/webgl/index-validation.html: Add a test case for large negative offset. git-svn-id: http://svn.webkit.org/repository/webkit/trunk@116374 268f45cc-cd09-0410-ab3c-d52691b4dbfc https://www.codeaurora.org/gitweb/quic/la/?p=platform/external/webkit.git;a=commit;h=b3a02a0942a0e2c44d23961382145fad6016b2ef Fix for context-attributes-alpha-depth-stencil-antialias Support for alpha, depth and stencil to fix WebGL Khronos 1.0.1 conformance test. Report back that antialiasing is not supported on our platform. https://www.codeaurora.org/gitweb/quic/la/?p=platform/external/webkit.git;a=commit;h=22e98195ac73e7e12a59d5b9a42dfc4e2252b475 WebGLRenderingContext should defer caching program info https://bugs.webkit.org/show_bug.cgi?id=83513 Reviewed by Kenneth Russell. * html/canvas/WebGLProgram.cpp: (WebCore::WebGLProgram::WebGLProgram): (WebCore::WebGLProgram::numActiveAttribLocations): call cacheInfoIfNeeded(); (WebCore::WebGLProgram::getActiveAttribLocation): Ditto. (WebCore::WebGLProgram::isUsingVertexAttrib0): Ditto. (WebCore::WebGLProgram::getLinkStatus): Ditto. (WebCore): (WebCore::WebGLProgram::cacheActiveAttribLocations): (WebCore::WebGLProgram::cacheInfoIfNeeded): Cache link status, active attire locations, etc if needed. (WebCore::WebGLProgram::increaseLinkCount): also invalidate cached info. * html/canvas/WebGLProgram.h: (WebGLProgram): * html/canvas/WebGLRenderingContext.cpp: (WebCore): (WebCore::WebGLRenderingContext::linkProgram): Do not cache program info immediately. git-svn-id: http://svn.webkit.org/repository/webkit/trunk@113915 268f45cc-cd09-0410-ab3c-d52691b4dbfc https://www.codeaurora.org/gitweb/quic/la/?p=platform/external/webkit.git;a=commit;h=66bc9c1b9eb5151b1b236199d0eeb17df0557b47 Runtime enablement of WebGL Hooks up with the Java side to enable/disable WebGL through the debug menu. https://www.codeaurora.org/gitweb/quic/la/?p=platform/external/webkit.git;a=commit;h=75aab57859de45a0aaec5a7cad41a12111e9a82e Support the usage of CORS for WebGL and the 2D canvas Factor CORS request preparation out of DocumentThreadableLoader https://bugs.webkit.org/show_bug.cgi?id=61209 2011-05-20 Adam Barth <abarth@webkit.org> Reviewed by Alexey Proskuryakov. Factor CORS request preparation out of DocumentThreadableLoader https://bugs.webkit.org/show_bug.cgi?id=61209 DocumentThreadableLoader has two jobs: 1) Proxy loads between threads. 2) Run the CORS state machine. This patch begins the work of separating those concerns, allowing CORS to be used elsewhere in the loading pipeline. In particular, this patch moves knowledge of how to prepare CORS requests out of DocumentThreadableLoder. * loader/CrossOriginAccessControl.cpp: (WebCore::isOnAccessControlSimpleRequestHeaderWhitelist): (WebCore::updateRequestForAccessControl): (WebCore::createAccessControlPreflightRequest): * loader/CrossOriginAccessControl.h: * loader/DocumentThreadableLoader.cpp: (WebCore::DocumentThreadableLoader::DocumentThreadableLoader): (WebCore::DocumentThreadableLoader::makeSimpleCrossOriginAccessRequest): (WebCore::DocumentThreadableLoader::makeCrossOriginAccessRequestWithPreflight): git-svn-id: http://svn.webkit.org/repository/webkit/trunk@86980 268f45cc-cd09-0410-ab3c-d52691b4dbfc Add rel type prerender to distinguish prerender from prefetch https://bugs.webkit.org/show_bug.cgi?id=61079 2011-05-21 Gavin Peters <gavinp@chromium.org> Reviewed by Adam Barth. Add rel type prerender to distinguish prerender from prefetch https://bugs.webkit.org/show_bug.cgi?id=61079 Chrome right now uses <link rel=prefetch ...> for one of two things, to warm the cache in the same way as firefox, or to launch a speculative rendering of a web page, for faster "loading" when the user navigates to it. This new rel type will let us distinguish the two cases; the rel type prerender isn't used on the web today, but the Google Web Search example prerendering application is ready to experiment with it. * fast/dom/HTMLLinkElement/prerender-expected.txt: Added. * fast/dom/HTMLLinkElement/prerender.html: Added. * platform/gtk/Skipped: * platform/mac/Skipped: * platform/qt/Skipped: * platform/win/Skipped: 2011-05-21 Gavin Peters <gavinp@chromium.org> Reviewed by Adam Barth. Add rel type prerender to distinguish prerender from prefetch https://bugs.webkit.org/show_bug.cgi?id=61079 Chrome right now uses <link rel=prefetch ...> for one of two things, to warm the cache in the same way as firefox, or to launch a speculative rendering of a web page, for faster "loading" when the user navigates to it. This new rel type will let us distinguish the two cases; the rel type prerender isn't used on the web today, but the Google Web Search example prerendering application is ready to experiment with it. Test: fast/dom/HTMLLinkElement/prerender.html * html/HTMLLinkElement.cpp: (WebCore::HTMLLinkElement::tokenizeRelAttribute): (WebCore::HTMLLinkElement::process): * html/HTMLLinkElement.h: (WebCore::HTMLLinkElement::RelAttribute::RelAttribute): * loader/cache/CachedResource.cpp: (WebCore::defaultPriorityForResourceType): * loader/cache/CachedResource.h: (WebCore::CachedResource::isLinkResource): * loader/cache/CachedResourceLoader.cpp: (WebCore::createResource): (WebCore::CachedResourceLoader::requestLinkResource): (WebCore::CachedResourceLoader::canRequest): * loader/cache/CachedResourceLoader.h: * loader/cache/CachedResourceRequest.cpp: (WebCore::cachedResourceTypeToTargetType): (WebCore::CachedResourceRequest::load): * platform/network/ResourceRequestBase.h: git-svn-id: http://svn.webkit.org/repository/webkit/trunk@87020 268f45cc-cd09-0410-ab3c-d52691b4dbfc Make CachedResource take a ResourceRequest instead of just a url string. 2011-05-24 Nate Chapin <japhet@chromium.org> Reviewed by Adam Barth. Change CachedResources to take a ResourceRequest instead of a url in their constructors and provide a very minimal set of cases for avoiding reusing a CachedResource. The ResourceRequest part of this change requires pushing responsibility for calling Document::completeURL() to the caller, instead of CachedResourceLoader, since ResourceRequest ASSERTs if it is constructed with an invalid url. https://bugs.webkit.org/show_bug.cgi?id=61318 Refactor, no new tests. * css/CSSFontSelector.cpp: (WebCore::CSSFontSelector::addFontFaceRule): * css/CSSImageValue.cpp: (WebCore::CSSImageValue::cachedImage): * css/CSSImportRule.cpp: (WebCore::CSSImportRule::insertedIntoParent): * dom/ProcessingInstruction.cpp: (WebCore::ProcessingInstruction::checkStyleSheet): * dom/ScriptElement.cpp: (WebCore::ScriptElement::requestScript): * html/HTMLLinkElement.cpp: (WebCore::HTMLLinkElement::process): * loader/ImageLoader.cpp: (WebCore::ImageLoader::updateFromElement): * loader/cache/CachedCSSStyleSheet.cpp: (WebCore::CachedCSSStyleSheet::CachedCSSStyleSheet): (WebCore::CachedCSSStyleSheet::didAddClient): (WebCore::CachedCSSStyleSheet::checkNotify): * loader/cache/CachedCSSStyleSheet.h: * loader/cache/CachedFont.cpp: (WebCore::CachedFont::CachedFont): * loader/cache/CachedFont.h: * loader/cache/CachedImage.cpp: (WebCore::CachedImage::CachedImage): (WebCore::CachedImage::checkShouldPaintBrokenImage): * loader/cache/CachedImage.h: * loader/cache/CachedResource.cpp: (WebCore::CachedResource::CachedResource): (WebCore::reuseRequest): (WebCore::CachedResource::allowReuseOfRequest): (WebCore::CachedResource::removeClient): (WebCore::CachedResource::canUseCacheValidator): * loader/cache/CachedResource.h: (WebCore::CachedResource::resourceRequest): (WebCore::CachedResource::url): * loader/cache/CachedResourceLoader.cpp: * loader/cache/CachedResourceLoader.h: * loader/cache/CachedResourceRequest.cpp: (WebCore::CachedResourceRequest::load): * loader/cache/CachedScript.cpp: (WebCore::CachedScript::CachedScript): * loader/cache/CachedScript.h: * loader/cache/CachedXSLStyleSheet.cpp: (WebCore::CachedXSLStyleSheet::CachedXSLStyleSheet): (WebCore::CachedXSLStyleSheet::didAddClient): (WebCore::CachedXSLStyleSheet::checkNotify): * loader/cache/CachedXSLStyleSheet.h: * svg/SVGFEImageElement.cpp: (WebCore::SVGFEImageElement::requestImageResource): * svg/SVGFontFaceUriElement.cpp: (WebCore::SVGFontFaceUriElement::loadFont): * xml/XSLImportRule.cpp: (WebCore::XSLImportRule::loadSheet): git-svn-id: http://svn.webkit.org/repository/webkit/trunk@87239 268f45cc-cd09-0410-ab3c-d52691b4dbfc Support cross-origin property for images 2011-05-26 Adam Barth <abarth@webkit.org> Reviewed by Eric Seidel. Support cross-origin property for images https://bugs.webkit.org/show_bug.cgi?id=61015 Test various cases involving CORS requests and canvas tainting. * http/tests/security/canvas-remote-read-remote-image-allowed-expected.txt: Added. * http/tests/security/canvas-remote-read-remote-image-allowed-with-credentials-expected.txt: Added. * http/tests/security/canvas-remote-read-remote-image-allowed-with-credentials.html: Added. * http/tests/security/canvas-remote-read-remote-image-allowed.html: Added. * http/tests/security/canvas-remote-read-remote-image-blocked-no-crossorigin-expected.txt: Added. * http/tests/security/canvas-remote-read-remote-image-blocked-no-crossorigin.html: Added. * http/tests/security/resources/abe-allow-credentials.php: Added. * http/tests/security/resources/abe-allow-star.php: Added. 2011-05-26 Adam Barth <abarth@webkit.org> Reviewed by Eric Seidel. Support cross-origin property for images https://bugs.webkit.org/show_bug.cgi?id=61015 This patch add support for the crossorigin attribute of images and teaches 2D canvas to respect that flag and not taint a canvas if the image drawn on the canvas is allowed by CORS. While I was editing this code, I couldn't resist a couple touch-up changes. Tests: http/tests/security/canvas-remote-read-remote-image-allowed-with-credentials.html http/tests/security/canvas-remote-read-remote-image-allowed.html http/tests/security/canvas-remote-read-remote-image-blocked-no-crossorigin.html * html/HTMLAttributeNames.in: * html/HTMLCanvasElement.cpp: (WebCore::HTMLCanvasElement::securityOrigin): * html/HTMLCanvasElement.h: * html/HTMLImageElement.idl: * html/canvas/CanvasRenderingContext.cpp: (WebCore::CanvasRenderingContext::checkOrigin): * html/canvas/CanvasRenderingContext2D.cpp: (WebCore::CanvasRenderingContext2D::createPattern): * loader/ImageLoader.cpp: (WebCore::ImageLoader::updateFromElement): * loader/cache/CachedResource.cpp: (WebCore::CachedResource::passesAccessControlCheck): * loader/cache/CachedResource.h: git-svn-id: http://svn.webkit.org/repository/webkit/trunk@87473 268f45cc-cd09-0410-ab3c-d52691b4dbfc HTMLVideoElement::currentSrc() should return a KURL 2011-05-27 Adam Barth <abarth@webkit.org> Reviewed by Eric Seidel. HTMLVideoElement::currentSrc() should return a KURL https://bugs.webkit.org/show_bug.cgi?id=61578 I suspect we got into this mess because the author of this code didn't know about the URL attribute in WebKit IDL, which is super useful! Bad news: The line of code in question seems to have another bug, which I've documented in a FIXME. Let the yak shaving continue! * html/HTMLMediaElement.cpp: (WebCore::urlForLogging): (WebCore::HTMLMediaElement::loadResource): (WebCore::HTMLMediaElement::isSafeToLoadURL): (WebCore::HTMLMediaElement::selectNextSourceChild): (WebCore::HTMLMediaElement::getPluginProxyParams): * html/HTMLMediaElement.h: (WebCore::HTMLMediaElement::currentSrc): (WebCore::HTMLMediaElement::currentURL): * html/canvas/CanvasRenderingContext.cpp: (WebCore::CanvasRenderingContext::checkOrigin): * rendering/HitTestResult.cpp: (WebCore::HitTestResult::absoluteMediaURL): - This complete URL call was unnecessary because currentSrc is already absolute. git-svn-id: http://svn.webkit.org/repository/webkit/trunk@87539 268f45cc-cd09-0410-ab3c-d52691b4dbfc Disallow use of cross-domain media (images, video) in WebGL 2011-06-09 Kenneth Russell <kbr@google.com> Reviewed by Adam Barth. Disallow use of cross-domain media (images, video) in WebGL https://bugs.webkit.org/show_bug.cgi?id=62257 Updated WebGL implementation to track recent spec updates in this area. Tests: http/tests/security/webgl-remote-read-remote-image-allowed-with-credentials.html http/tests/security/webgl-remote-read-remote-image-allowed.html http/tests/security/webgl-remote-read-remote-image-blocked-no-crossorigin.html * html/canvas/CanvasRenderingContext.cpp: (WebCore::CanvasRenderingContext::wouldTaintOrigin): (WebCore::CanvasRenderingContext::checkOrigin): * html/canvas/CanvasRenderingContext.h: (WebCore::CanvasRenderingContext::checkOrigin): * html/canvas/WebGLRenderingContext.cpp: (WebCore::WebGLRenderingContext::readPixels): (WebCore::WebGLRenderingContext::texImage2D): (WebCore::WebGLRenderingContext::videoFrameToImage): (WebCore::WebGLRenderingContext::texSubImage2D): * html/canvas/WebGLRenderingContext.h: 2011-06-09 Kenneth Russell <kbr@google.com> Reviewed by Adam Barth. Disallow use of cross-domain media (images, video) in WebGL https://bugs.webkit.org/show_bug.cgi?id=62257 Updated origin-clean-conformance.html to track upstream version in Khronos repository. Added new layout tests mirroring those added in bug 61015 which verify that new CORS support for images is working in the context of WebGL. Verified new tests in WebKit and Chromium. Skipped tests on platforms where WebGL is disabled. * http/tests/canvas/webgl/origin-clean-conformance-expected.txt: * http/tests/canvas/webgl/origin-clean-conformance.html: * http/tests/security/webgl-remote-read-remote-image-allowed-expected.txt: Added. * http/tests/security/webgl-remote-read-remote-image-allowed-with-credentials-expected.txt: Added. * http/tests/security/webgl-remote-read-remote-image-allowed-with-credentials.html: Added. * http/tests/security/webgl-remote-read-remote-image-allowed.html: Added. * http/tests/security/webgl-remote-read-remote-image-blocked-no-crossorigin-expected.txt: Added. * http/tests/security/webgl-remote-read-remote-image-blocked-no-crossorigin.html: Added. * platform/gtk/Skipped: * platform/mac-leopard/Skipped: * platform/mac-wk2/Skipped: * platform/qt/Skipped: git-svn-id: http://svn.webkit.org/repository/webkit/trunk@88489 268f45cc-cd09-0410-ab3c-d52691b4dbfc https://www.codeaurora.org/gitweb/quic/la/?p=platform/external/webkit.git;a=commit;h=0ddd7c1d91c08fbee6c99b79fa9971a7ac914384 Runtime enablement of WebGL logs Allows enabling WebGL method level logging using: adb shell setprop debug.webgl 1 https://www.codeaurora.org/gitweb/quic/la/?p=platform/external/webkit.git;a=commit;h=307d4a2b5b20f2609497ceaea1eca2e29a8a781f Adding WebGL FPS timing to logs Samples WebGL average FPS every 15 frames and outputs to WebGL debug log. TODO: Add setting to browser debug settings that overlays FPS on web pages. Postpone deleteRenderbuffer/deleteTexture until all framebuffer attachment points are removed. https://bugs.webkit.org/show_bug.cgi?id=74741 Reviewed by Kenneth Russell. Source/WebCore: Use WebGLObject's attachment count mechanism to track if a renderbuffer/texture is still attached to framebuffers, and if its deletion should be delated or not. * html/canvas/WebGLFramebuffer.cpp: (WebCore::WebGLFramebuffer::setAttachmentForBoundFramebuffer): (WebCore::WebGLFramebuffer::getAttachment): (WebCore::WebGLFramebuffer::removeAttachmentFromBoundFramebuffer): (WebCore::WebGLFramebuffer::deleteObjectImpl): (WebCore::WebGLFramebuffer::isBound): * html/canvas/WebGLFramebuffer.h: LayoutTests: * fast/canvas/webgl/object-deletion-behaviour-expected.txt: * fast/canvas/webgl/object-deletion-behaviour.html: synced with khronos side. git-svn-id: http://svn.webkit.org/repository/webkit/trunk@103272 268f45cc-cd09-0410-ab3c-d52691b4dbfc https://www.codeaurora.org/gitweb/quic/la/?p=platform/external/webkit.git;a=commit;h=9def386340c74f2a745fb041b1cb11daa30d1a82 ----------------------------------------------------------- (cherry-picked from commit 6d9d732ff06a6b265d02b18d7034068a68ef0fde) Conflicts: Android.mk Source/WebCore/ChangeLog Change-Id: I3bbf993fe5a3d6cea53e019c8fa3912ecd2bd429
Diffstat (limited to 'Source/ThirdParty/ANGLE/src/libGLESv2/Context.cpp')
-rw-r--r--Source/ThirdParty/ANGLE/src/libGLESv2/Context.cpp1926
1 files changed, 1310 insertions, 616 deletions
diff --git a/Source/ThirdParty/ANGLE/src/libGLESv2/Context.cpp b/Source/ThirdParty/ANGLE/src/libGLESv2/Context.cpp
index 9be59c4..66cd5c0 100644
--- a/Source/ThirdParty/ANGLE/src/libGLESv2/Context.cpp
+++ b/Source/ThirdParty/ANGLE/src/libGLESv2/Context.cpp
@@ -1,5 +1,5 @@
//
-// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
+// Copyright (c) 2002-2012 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
@@ -22,20 +22,27 @@
#include "libGLESv2/Fence.h"
#include "libGLESv2/FrameBuffer.h"
#include "libGLESv2/Program.h"
+#include "libGLESv2/Query.h"
#include "libGLESv2/RenderBuffer.h"
#include "libGLESv2/Shader.h"
#include "libGLESv2/Texture.h"
-#include "libGLESv2/geometry/VertexDataManager.h"
-#include "libGLESv2/geometry/IndexDataManager.h"
+#include "libGLESv2/VertexDataManager.h"
+#include "libGLESv2/IndexDataManager.h"
#undef near
#undef far
namespace gl
{
-Context::Context(const egl::Config *config, const gl::Context *shareContext)
- : mConfig(config)
+Context::Context(const egl::Config *config, const gl::Context *shareContext, bool notifyResets, bool robustAccess) : mConfig(config)
{
+ ASSERT(robustAccess == false); // Unimplemented
+
+ mDisplay = NULL;
+ mDevice = NULL;
+
+ mFenceHandleAllocator.setBaseHandle(0);
+
setClearColor(0.0f, 0.0f, 0.0f, 0.0f);
mState.depthClearValue = 1.0f;
@@ -136,10 +143,12 @@ Context::Context(const egl::Config *config, const gl::Context *shareContext)
mState.packAlignment = 4;
mState.unpackAlignment = 4;
+ mState.packReverseRowOrder = false;
mVertexDataManager = NULL;
mIndexDataManager = NULL;
mBlit = NULL;
+ mLineLoopIB = NULL;
mInvalidEnum = false;
mInvalidValue = false;
@@ -148,9 +157,17 @@ Context::Context(const egl::Config *config, const gl::Context *shareContext)
mInvalidFramebufferOperation = false;
mHasBeenCurrent = false;
-
- mSupportsCompressedTextures = false;
+ mContextLost = false;
+ mResetStatus = GL_NO_ERROR;
+ mResetStrategy = (notifyResets ? GL_LOSE_CONTEXT_ON_RESET_EXT : GL_NO_RESET_NOTIFICATION_EXT);
+ mRobustAccess = robustAccess;
+
+ mSupportsDXT1Textures = false;
+ mSupportsDXT3Textures = false;
+ mSupportsDXT5Textures = false;
mSupportsEventQueries = false;
+ mSupportsOcclusionQueries = false;
+ mNumCompressedTextureFormats = 0;
mMaxSupportedSamples = 0;
mMaskedClearSavedState = NULL;
markAllStateDirty();
@@ -178,21 +195,26 @@ Context::~Context()
deleteFence(mFenceMap.begin()->first);
}
+ while (!mQueryMap.empty())
+ {
+ deleteQuery(mQueryMap.begin()->first);
+ }
+
while (!mMultiSampleSupport.empty())
{
delete [] mMultiSampleSupport.begin()->second;
mMultiSampleSupport.erase(mMultiSampleSupport.begin());
}
- for (int type = 0; type < SAMPLER_TYPE_COUNT; type++)
+ for (int type = 0; type < TEXTURE_TYPE_COUNT; type++)
{
- for (int sampler = 0; sampler < MAX_TEXTURE_IMAGE_UNITS; sampler++)
+ for (int sampler = 0; sampler < MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF; sampler++)
{
mState.samplerTexture[type][sampler].set(NULL);
}
}
- for (int type = 0; type < SAMPLER_TYPE_COUNT; type++)
+ for (int type = 0; type < TEXTURE_TYPE_COUNT; type++)
{
mIncompleteTextures[type].set(NULL);
}
@@ -202,6 +224,11 @@ Context::~Context()
mState.vertexAttribute[i].mBoundBuffer.set(NULL);
}
+ for (int i = 0; i < QUERY_TYPE_COUNT; i++)
+ {
+ mState.activeQuery[i].set(NULL);
+ }
+
mState.arrayBuffer.set(NULL);
mState.elementArrayBuffer.set(NULL);
mState.renderbuffer.set(NULL);
@@ -212,6 +239,7 @@ Context::~Context()
delete mVertexDataManager;
delete mIndexDataManager;
delete mBlit;
+ delete mLineLoopIB;
if (mMaskedClearSavedState)
{
@@ -223,17 +251,21 @@ Context::~Context()
void Context::makeCurrent(egl::Display *display, egl::Surface *surface)
{
- IDirect3DDevice9 *device = display->getDevice();
+ mDisplay = display;
+ mDevice = mDisplay->getDevice();
if (!mHasBeenCurrent)
{
- mDeviceCaps = display->getDeviceCaps();
+ mDeviceCaps = mDisplay->getDeviceCaps();
- mVertexDataManager = new VertexDataManager(this, device);
- mIndexDataManager = new IndexDataManager(this, device);
+ mVertexDataManager = new VertexDataManager(this, mDevice);
+ mIndexDataManager = new IndexDataManager(this, mDevice);
mBlit = new Blit(this);
- mSupportsShaderModel3 = mDeviceCaps.PixelShaderVersion == D3DPS_VERSION(3, 0);
+ mSupportsShaderModel3 = mDeviceCaps.PixelShaderVersion >= D3DPS_VERSION(3, 0);
+ mSupportsVertexTexture = mDisplay->getVertexTextureSupport();
+ mSupportsNonPower2Texture = mDisplay->getNonPower2TextureSupport();
+ mSupportsInstancing = mDisplay->getInstancingSupport();
mMaxTextureDimension = std::min(std::min((int)mDeviceCaps.MaxTextureWidth, (int)mDeviceCaps.MaxTextureHeight),
(int)gl::IMPLEMENTATION_MAX_TEXTURE_SIZE);
@@ -255,7 +287,7 @@ void Context::makeCurrent(egl::Display *display, egl::Surface *surface)
for (int i = 0; i < sizeof(renderBufferFormats) / sizeof(D3DFORMAT); ++i)
{
bool *multisampleArray = new bool[D3DMULTISAMPLE_16_SAMPLES + 1];
- display->getMultiSampleSupport(renderBufferFormats[i], multisampleArray);
+ mDisplay->getMultiSampleSupport(renderBufferFormats[i], multisampleArray);
mMultiSampleSupport[renderBufferFormats[i]] = multisampleArray;
for (int j = D3DMULTISAMPLE_16_SAMPLES; j >= 0; --j)
@@ -269,16 +301,34 @@ void Context::makeCurrent(egl::Display *display, egl::Surface *surface)
mMaxSupportedSamples = max;
- mSupportsEventQueries = display->getEventQuerySupport();
- mSupportsCompressedTextures = display->getCompressedTextureSupport();
- mSupportsFloatTextures = display->getFloatTextureSupport(&mSupportsFloatLinearFilter, &mSupportsFloatRenderableTextures);
- mSupportsHalfFloatTextures = display->getHalfFloatTextureSupport(&mSupportsHalfFloatLinearFilter, &mSupportsHalfFloatRenderableTextures);
- mSupportsLuminanceTextures = display->getLuminanceTextureSupport();
- mSupportsLuminanceAlphaTextures = display->getLuminanceAlphaTextureSupport();
+ mSupportsEventQueries = mDisplay->getEventQuerySupport();
+ mSupportsOcclusionQueries = mDisplay->getOcclusionQuerySupport();
+ mSupportsDXT1Textures = mDisplay->getDXT1TextureSupport();
+ mSupportsDXT3Textures = mDisplay->getDXT3TextureSupport();
+ mSupportsDXT5Textures = mDisplay->getDXT5TextureSupport();
+ mSupportsFloat32Textures = mDisplay->getFloat32TextureSupport(&mSupportsFloat32LinearFilter, &mSupportsFloat32RenderableTextures);
+ mSupportsFloat16Textures = mDisplay->getFloat16TextureSupport(&mSupportsFloat16LinearFilter, &mSupportsFloat16RenderableTextures);
+ mSupportsLuminanceTextures = mDisplay->getLuminanceTextureSupport();
+ mSupportsLuminanceAlphaTextures = mDisplay->getLuminanceAlphaTextureSupport();
mSupports32bitIndices = mDeviceCaps.MaxVertexIndex >= (1 << 16);
+ mNumCompressedTextureFormats = 0;
+ if (supportsDXT1Textures())
+ {
+ mNumCompressedTextureFormats += 2;
+ }
+ if (supportsDXT3Textures())
+ {
+ mNumCompressedTextureFormats += 1;
+ }
+ if (supportsDXT5Textures())
+ {
+ mNumCompressedTextureFormats += 1;
+ }
+
initExtensionString();
+ initRendererString();
mState.viewportX = 0;
mState.viewportY = 0;
@@ -319,11 +369,26 @@ void Context::makeCurrent(egl::Display *display, egl::Surface *surface)
// This function will set all of the state-related dirty flags, so that all state is set during next pre-draw.
void Context::markAllStateDirty()
{
+ for (int t = 0; t < MAX_TEXTURE_IMAGE_UNITS; t++)
+ {
+ mAppliedTextureSerialPS[t] = 0;
+ }
+
+ for (int t = 0; t < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; t++)
+ {
+ mAppliedTextureSerialVS[t] = 0;
+ }
+
+ mAppliedProgramSerial = 0;
mAppliedRenderTargetSerial = 0;
mAppliedDepthbufferSerial = 0;
mAppliedStencilbufferSerial = 0;
+ mAppliedIBSerial = 0;
mDepthStencilInitialized = false;
- mAppliedProgram = 0;
+ mViewportInitialized = false;
+ mRenderTargetDescInitialized = false;
+
+ mVertexDeclarationCache.markStateDirty();
mClearStateDirty = true;
mCullStateDirty = true;
@@ -336,6 +401,20 @@ void Context::markAllStateDirty()
mSampleStateDirty = true;
mDitherStateDirty = true;
mFrontFaceDirty = true;
+ mDxUniformsDirty = true;
+ mCachedCurrentProgram = NULL;
+}
+
+void Context::markContextLost()
+{
+ if (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT)
+ mResetStatus = GL_UNKNOWN_CONTEXT_RESET_EXT;
+ mContextLost = true;
+}
+
+bool Context::isContextLost()
+{
+ return mContextLost;
}
void Context::setClearColor(float red, float green, float blue, float alpha)
@@ -710,7 +789,7 @@ void Context::setDepthMask(bool mask)
}
}
-void Context::setActiveSampler(int active)
+void Context::setActiveSampler(unsigned int active)
{
mState.activeSampler = active;
}
@@ -735,6 +814,32 @@ GLuint Context::getArrayBufferHandle() const
return mState.arrayBuffer.id();
}
+GLuint Context::getActiveQuery(GLenum target) const
+{
+ Query *queryObject = NULL;
+
+ switch (target)
+ {
+ case GL_ANY_SAMPLES_PASSED_EXT:
+ queryObject = mState.activeQuery[QUERY_ANY_SAMPLES_PASSED].get();
+ break;
+ case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
+ queryObject = mState.activeQuery[QUERY_ANY_SAMPLES_PASSED_CONSERVATIVE].get();
+ break;
+ default:
+ ASSERT(false);
+ }
+
+ if (queryObject)
+ {
+ return queryObject->id();
+ }
+ else
+ {
+ return 0;
+ }
+}
+
void Context::setEnableVertexAttribArray(unsigned int attribNum, bool enabled)
{
mState.vertexAttribute[attribNum].mArrayEnabled = enabled;
@@ -786,6 +891,16 @@ GLint Context::getUnpackAlignment() const
return mState.unpackAlignment;
}
+void Context::setPackReverseRowOrder(bool reverseRowOrder)
+{
+ mState.packReverseRowOrder = reverseRowOrder;
+}
+
+bool Context::getPackReverseRowOrder() const
+{
+ return mState.packReverseRowOrder;
+}
+
GLuint Context::createBuffer()
{
return mResourceManager->createBuffer();
@@ -814,12 +929,7 @@ GLuint Context::createRenderbuffer()
// Returns an unused framebuffer name
GLuint Context::createFramebuffer()
{
- unsigned int handle = 1;
-
- while (mFramebufferMap.find(handle) != mFramebufferMap.end())
- {
- handle++;
- }
+ GLuint handle = mFramebufferHandleAllocator.allocate();
mFramebufferMap[handle] = NULL;
@@ -828,14 +938,19 @@ GLuint Context::createFramebuffer()
GLuint Context::createFence()
{
- unsigned int handle = 0;
+ GLuint handle = mFenceHandleAllocator.allocate();
- while (mFenceMap.find(handle) != mFenceMap.end())
- {
- handle++;
- }
+ mFenceMap[handle] = new Fence(mDisplay);
- mFenceMap[handle] = new Fence;
+ return handle;
+}
+
+// Returns an unused query name
+GLuint Context::createQuery()
+{
+ GLuint handle = mQueryHandleAllocator.allocate();
+
+ mQueryMap[handle] = NULL;
return handle;
}
@@ -858,6 +973,7 @@ void Context::deleteShader(GLuint shader)
void Context::deleteProgram(GLuint program)
{
mResourceManager->deleteProgram(program);
+ mCachedCurrentProgram = NULL;
}
void Context::deleteTexture(GLuint texture)
@@ -888,6 +1004,7 @@ void Context::deleteFramebuffer(GLuint framebuffer)
{
detachFramebuffer(framebuffer);
+ mFramebufferHandleAllocator.release(framebufferObject->first);
delete framebufferObject->second;
mFramebufferMap.erase(framebufferObject);
}
@@ -899,11 +1016,26 @@ void Context::deleteFence(GLuint fence)
if (fenceObject != mFenceMap.end())
{
+ mFenceHandleAllocator.release(fenceObject->first);
delete fenceObject->second;
mFenceMap.erase(fenceObject);
}
}
+void Context::deleteQuery(GLuint query)
+{
+ QueryMap::iterator queryObject = mQueryMap.find(query);
+ if (queryObject != mQueryMap.end())
+ {
+ mQueryHandleAllocator.release(queryObject->first);
+ if (queryObject->second)
+ {
+ queryObject->second->release();
+ }
+ mQueryMap.erase(queryObject);
+ }
+}
+
Buffer *Context::getBuffer(GLuint handle)
{
return mResourceManager->getBuffer(handle);
@@ -936,7 +1068,7 @@ Framebuffer *Context::getReadFramebuffer()
Framebuffer *Context::getDrawFramebuffer()
{
- return getFramebuffer(mState.drawFramebuffer);
+ return mBoundDrawFramebuffer;
}
void Context::bindArrayBuffer(unsigned int buffer)
@@ -955,16 +1087,16 @@ void Context::bindElementArrayBuffer(unsigned int buffer)
void Context::bindTexture2D(GLuint texture)
{
- mResourceManager->checkTextureAllocation(texture, SAMPLER_2D);
+ mResourceManager->checkTextureAllocation(texture, TEXTURE_2D);
- mState.samplerTexture[SAMPLER_2D][mState.activeSampler].set(getTexture(texture));
+ mState.samplerTexture[TEXTURE_2D][mState.activeSampler].set(getTexture(texture));
}
void Context::bindTextureCubeMap(GLuint texture)
{
- mResourceManager->checkTextureAllocation(texture, SAMPLER_CUBE);
+ mResourceManager->checkTextureAllocation(texture, TEXTURE_CUBE);
- mState.samplerTexture[SAMPLER_CUBE][mState.activeSampler].set(getTexture(texture));
+ mState.samplerTexture[TEXTURE_CUBE][mState.activeSampler].set(getTexture(texture));
}
void Context::bindReadFramebuffer(GLuint framebuffer)
@@ -985,6 +1117,8 @@ void Context::bindDrawFramebuffer(GLuint framebuffer)
}
mState.drawFramebuffer = framebuffer;
+
+ mBoundDrawFramebuffer = getFramebuffer(framebuffer);
}
void Context::bindRenderbuffer(GLuint renderbuffer)
@@ -1003,6 +1137,8 @@ void Context::useProgram(GLuint program)
{
Program *newProgram = mResourceManager->getProgram(program);
Program *oldProgram = mResourceManager->getProgram(priorProgram);
+ mCachedCurrentProgram = NULL;
+ mDxUniformsDirty = true;
if (newProgram)
{
@@ -1016,10 +1152,103 @@ void Context::useProgram(GLuint program)
}
}
+void Context::beginQuery(GLenum target, GLuint query)
+{
+ // From EXT_occlusion_query_boolean: If BeginQueryEXT is called with an <id>
+ // of zero, if the active query object name for <target> is non-zero (for the
+ // targets ANY_SAMPLES_PASSED_EXT and ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, if
+ // the active query for either target is non-zero), if <id> is the name of an
+ // existing query object whose type does not match <target>, or if <id> is the
+ // active query object name for any query type, the error INVALID_OPERATION is
+ // generated.
+
+ // Ensure no other queries are active
+ // NOTE: If other queries than occlusion are supported, we will need to check
+ // separately that:
+ // a) The query ID passed is not the current active query for any target/type
+ // b) There are no active queries for the requested target (and in the case
+ // of GL_ANY_SAMPLES_PASSED_EXT and GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
+ // no query may be active for either if glBeginQuery targets either.
+ for (int i = 0; i < QUERY_TYPE_COUNT; i++)
+ {
+ if (mState.activeQuery[i].get() != NULL)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+
+ QueryType qType;
+ switch (target)
+ {
+ case GL_ANY_SAMPLES_PASSED_EXT:
+ qType = QUERY_ANY_SAMPLES_PASSED;
+ break;
+ case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
+ qType = QUERY_ANY_SAMPLES_PASSED_CONSERVATIVE;
+ break;
+ default:
+ ASSERT(false);
+ return;
+ }
+
+ Query *queryObject = getQuery(query, true, target);
+
+ // check that name was obtained with glGenQueries
+ if (!queryObject)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ // check for type mismatch
+ if (queryObject->getType() != target)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ // set query as active for specified target
+ mState.activeQuery[qType].set(queryObject);
+
+ // begin query
+ queryObject->begin();
+}
+
+void Context::endQuery(GLenum target)
+{
+ QueryType qType;
+
+ switch (target)
+ {
+ case GL_ANY_SAMPLES_PASSED_EXT:
+ qType = QUERY_ANY_SAMPLES_PASSED;
+ break;
+ case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
+ qType = QUERY_ANY_SAMPLES_PASSED_CONSERVATIVE;
+ break;
+ default:
+ ASSERT(false);
+ return;
+ }
+
+ Query *queryObject = mState.activeQuery[qType].get();
+
+ if (queryObject == NULL)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+
+ queryObject->end();
+
+ mState.activeQuery[qType].set(NULL);
+}
+
void Context::setFramebufferZero(Framebuffer *buffer)
{
delete mFramebufferMap[0];
mFramebufferMap[0] = buffer;
+ if (mState.drawFramebuffer == 0)
+ {
+ mBoundDrawFramebuffer = buffer;
+ }
}
void Context::setRenderbufferStorage(RenderbufferStorage *renderbuffer)
@@ -1056,6 +1285,25 @@ Fence *Context::getFence(unsigned int handle)
}
}
+Query *Context::getQuery(unsigned int handle, bool create, GLenum type)
+{
+ QueryMap::iterator query = mQueryMap.find(handle);
+
+ if (query == mQueryMap.end())
+ {
+ return NULL;
+ }
+ else
+ {
+ if (!query->second && create)
+ {
+ query->second = new Query(handle, type);
+ query->second->addRef();
+ }
+ return query->second;
+ }
+}
+
Buffer *Context::getArrayBuffer()
{
return mState.arrayBuffer.get();
@@ -1068,20 +1316,24 @@ Buffer *Context::getElementArrayBuffer()
Program *Context::getCurrentProgram()
{
- return mResourceManager->getProgram(mState.currentProgram);
+ if (!mCachedCurrentProgram)
+ {
+ mCachedCurrentProgram = mResourceManager->getProgram(mState.currentProgram);
+ }
+ return mCachedCurrentProgram;
}
Texture2D *Context::getTexture2D()
{
- return static_cast<Texture2D*>(getSamplerTexture(mState.activeSampler, SAMPLER_2D));
+ return static_cast<Texture2D*>(getSamplerTexture(mState.activeSampler, TEXTURE_2D));
}
TextureCubeMap *Context::getTextureCubeMap()
{
- return static_cast<TextureCubeMap*>(getSamplerTexture(mState.activeSampler, SAMPLER_CUBE));
+ return static_cast<TextureCubeMap*>(getSamplerTexture(mState.activeSampler, TEXTURE_CUBE));
}
-Texture *Context::getSamplerTexture(unsigned int sampler, SamplerType type)
+Texture *Context::getSamplerTexture(unsigned int sampler, TextureType type)
{
GLuint texid = mState.samplerTexture[type][sampler].id();
@@ -1090,8 +1342,8 @@ Texture *Context::getSamplerTexture(unsigned int sampler, SamplerType type)
switch (type)
{
default: UNREACHABLE();
- case SAMPLER_2D: return mTexture2DZero.get();
- case SAMPLER_CUBE: return mTextureCubeMapZero.get();
+ case TEXTURE_2D: return mTexture2DZero.get();
+ case TEXTURE_CUBE: return mTextureCubeMapZero.get();
}
}
@@ -1102,24 +1354,25 @@ bool Context::getBooleanv(GLenum pname, GLboolean *params)
{
switch (pname)
{
- case GL_SHADER_COMPILER: *params = GL_TRUE; break;
- case GL_SAMPLE_COVERAGE_INVERT: *params = mState.sampleCoverageInvert; break;
- case GL_DEPTH_WRITEMASK: *params = mState.depthMask; break;
+ case GL_SHADER_COMPILER: *params = GL_TRUE; break;
+ case GL_SAMPLE_COVERAGE_INVERT: *params = mState.sampleCoverageInvert; break;
+ case GL_DEPTH_WRITEMASK: *params = mState.depthMask; break;
case GL_COLOR_WRITEMASK:
params[0] = mState.colorMaskRed;
params[1] = mState.colorMaskGreen;
params[2] = mState.colorMaskBlue;
params[3] = mState.colorMaskAlpha;
break;
- case GL_CULL_FACE: *params = mState.cullFace; break;
- case GL_POLYGON_OFFSET_FILL: *params = mState.polygonOffsetFill; break;
- case GL_SAMPLE_ALPHA_TO_COVERAGE: *params = mState.sampleAlphaToCoverage; break;
- case GL_SAMPLE_COVERAGE: *params = mState.sampleCoverage; break;
- case GL_SCISSOR_TEST: *params = mState.scissorTest; break;
- case GL_STENCIL_TEST: *params = mState.stencilTest; break;
- case GL_DEPTH_TEST: *params = mState.depthTest; break;
- case GL_BLEND: *params = mState.blend; break;
- case GL_DITHER: *params = mState.dither; break;
+ case GL_CULL_FACE: *params = mState.cullFace; break;
+ case GL_POLYGON_OFFSET_FILL: *params = mState.polygonOffsetFill; break;
+ case GL_SAMPLE_ALPHA_TO_COVERAGE: *params = mState.sampleAlphaToCoverage; break;
+ case GL_SAMPLE_COVERAGE: *params = mState.sampleCoverage; break;
+ case GL_SCISSOR_TEST: *params = mState.scissorTest; break;
+ case GL_STENCIL_TEST: *params = mState.stencilTest; break;
+ case GL_DEPTH_TEST: *params = mState.depthTest; break;
+ case GL_BLEND: *params = mState.blend; break;
+ case GL_DITHER: *params = mState.dither; break;
+ case GL_CONTEXT_ROBUST_ACCESS_EXT: *params = mRobustAccess ? GL_TRUE : GL_FALSE; break;
default:
return false;
}
@@ -1183,8 +1436,8 @@ bool Context::getIntegerv(GLenum pname, GLint *params)
case GL_MAX_VERTEX_ATTRIBS: *params = gl::MAX_VERTEX_ATTRIBS; break;
case GL_MAX_VERTEX_UNIFORM_VECTORS: *params = gl::MAX_VERTEX_UNIFORM_VECTORS; break;
case GL_MAX_VARYING_VECTORS: *params = getMaximumVaryingVectors(); break;
- case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: *params = gl::MAX_COMBINED_TEXTURE_IMAGE_UNITS; break;
- case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: *params = gl::MAX_VERTEX_TEXTURE_IMAGE_UNITS; break;
+ case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: *params = getMaximumCombinedTextureImageUnits(); break;
+ case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: *params = getMaximumVertexTextureImageUnits(); break;
case GL_MAX_TEXTURE_IMAGE_UNITS: *params = gl::MAX_TEXTURE_IMAGE_UNITS; break;
case GL_MAX_FRAGMENT_UNIFORM_VECTORS: *params = getMaximumFragmentUniformVectors(); break;
case GL_MAX_RENDERBUFFER_SIZE: *params = getMaximumRenderbufferDimension(); break;
@@ -1198,6 +1451,7 @@ bool Context::getIntegerv(GLenum pname, GLint *params)
case GL_RENDERBUFFER_BINDING: *params = mState.renderbuffer.id(); break;
case GL_CURRENT_PROGRAM: *params = mState.currentProgram; break;
case GL_PACK_ALIGNMENT: *params = mState.packAlignment; break;
+ case GL_PACK_REVERSE_ROW_ORDER_ANGLE: *params = mState.packReverseRowOrder; break;
case GL_UNPACK_ALIGNMENT: *params = mState.unpackAlignment; break;
case GL_GENERATE_MIPMAP_HINT: *params = mState.generateMipmapHint; break;
case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES: *params = mState.fragmentShaderDerivativeHint; break;
@@ -1228,18 +1482,7 @@ bool Context::getIntegerv(GLenum pname, GLint *params)
case GL_MAX_TEXTURE_SIZE: *params = getMaximumTextureDimension(); break;
case GL_MAX_CUBE_MAP_TEXTURE_SIZE: *params = getMaximumCubeTextureDimension(); break;
case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
- {
- if (supportsCompressedTextures())
- {
- // at current, only GL_COMPRESSED_RGB_S3TC_DXT1_EXT and
- // GL_COMPRESSED_RGBA_S3TC_DXT1_EXT are supported
- *params = 2;
- }
- else
- {
- *params = 0;
- }
- }
+ params[0] = mNumCompressedTextureFormats;
break;
case GL_MAX_SAMPLES_ANGLE:
{
@@ -1295,10 +1538,18 @@ bool Context::getIntegerv(GLenum pname, GLint *params)
break;
case GL_COMPRESSED_TEXTURE_FORMATS:
{
- if (supportsCompressedTextures())
+ if (supportsDXT1Textures())
+ {
+ *params++ = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
+ *params++ = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+ }
+ if (supportsDXT3Textures())
+ {
+ *params++ = GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE;
+ }
+ if (supportsDXT5Textures())
{
- params[0] = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
- params[1] = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+ *params++ = GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE;
}
}
break;
@@ -1322,7 +1573,7 @@ bool Context::getIntegerv(GLenum pname, GLint *params)
case GL_ALPHA_BITS:
{
gl::Framebuffer *framebuffer = getDrawFramebuffer();
- gl::Colorbuffer *colorbuffer = framebuffer->getColorbuffer();
+ gl::Renderbuffer *colorbuffer = framebuffer->getColorbuffer();
if (colorbuffer)
{
@@ -1343,7 +1594,7 @@ bool Context::getIntegerv(GLenum pname, GLint *params)
case GL_DEPTH_BITS:
{
gl::Framebuffer *framebuffer = getDrawFramebuffer();
- gl::DepthStencilbuffer *depthbuffer = framebuffer->getDepthbuffer();
+ gl::Renderbuffer *depthbuffer = framebuffer->getDepthbuffer();
if (depthbuffer)
{
@@ -1358,7 +1609,7 @@ bool Context::getIntegerv(GLenum pname, GLint *params)
case GL_STENCIL_BITS:
{
gl::Framebuffer *framebuffer = getDrawFramebuffer();
- gl::DepthStencilbuffer *stencilbuffer = framebuffer->getStencilbuffer();
+ gl::Renderbuffer *stencilbuffer = framebuffer->getStencilbuffer();
if (stencilbuffer)
{
@@ -1372,26 +1623,29 @@ bool Context::getIntegerv(GLenum pname, GLint *params)
break;
case GL_TEXTURE_BINDING_2D:
{
- if (mState.activeSampler < 0 || mState.activeSampler > gl::MAX_TEXTURE_IMAGE_UNITS - 1)
+ if (mState.activeSampler < 0 || mState.activeSampler > getMaximumCombinedTextureImageUnits() - 1)
{
error(GL_INVALID_OPERATION);
return false;
}
- *params = mState.samplerTexture[SAMPLER_2D][mState.activeSampler].id();
+ *params = mState.samplerTexture[TEXTURE_2D][mState.activeSampler].id();
}
break;
case GL_TEXTURE_BINDING_CUBE_MAP:
{
- if (mState.activeSampler < 0 || mState.activeSampler > gl::MAX_TEXTURE_IMAGE_UNITS - 1)
+ if (mState.activeSampler < 0 || mState.activeSampler > getMaximumCombinedTextureImageUnits() - 1)
{
error(GL_INVALID_OPERATION);
return false;
}
- *params = mState.samplerTexture[SAMPLER_CUBE][mState.activeSampler].id();
+ *params = mState.samplerTexture[TEXTURE_CUBE][mState.activeSampler].id();
}
break;
+ case GL_RESET_NOTIFICATION_STRATEGY_EXT:
+ *params = mResetStrategy;
+ break;
default:
return false;
}
@@ -1410,7 +1664,12 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu
// application.
switch (pname)
{
- case GL_COMPRESSED_TEXTURE_FORMATS: /* no compressed texture formats are supported */
+ case GL_COMPRESSED_TEXTURE_FORMATS:
+ {
+ *type = GL_INT;
+ *numParams = mNumCompressedTextureFormats;
+ }
+ break;
case GL_SHADER_BINARY_FORMATS:
{
*type = GL_INT;
@@ -1432,6 +1691,7 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu
case GL_RENDERBUFFER_BINDING:
case GL_CURRENT_PROGRAM:
case GL_PACK_ALIGNMENT:
+ case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
case GL_UNPACK_ALIGNMENT:
case GL_GENERATE_MIPMAP_HINT:
case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES:
@@ -1476,6 +1736,7 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu
case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
case GL_TEXTURE_BINDING_2D:
case GL_TEXTURE_BINDING_CUBE_MAP:
+ case GL_RESET_NOTIFICATION_STRATEGY_EXT:
{
*type = GL_INT;
*numParams = 1;
@@ -1519,6 +1780,7 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu
case GL_DEPTH_TEST:
case GL_BLEND:
case GL_DITHER:
+ case GL_CONTEXT_ROBUST_ACCESS_EXT:
{
*type = GL_BOOL;
*numParams = 1;
@@ -1566,34 +1828,30 @@ bool Context::getQueryParameterInfo(GLenum pname, GLenum *type, unsigned int *nu
// scissor rectangle to the Direct3D 9 device
bool Context::applyRenderTarget(bool ignoreViewport)
{
- IDirect3DDevice9 *device = getDevice();
-
Framebuffer *framebufferObject = getDrawFramebuffer();
if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE)
{
- error(GL_INVALID_FRAMEBUFFER_OPERATION);
-
- return false;
+ return error(GL_INVALID_FRAMEBUFFER_OPERATION, false);
}
- IDirect3DSurface9 *renderTarget = framebufferObject->getRenderTarget();
-
- if (!renderTarget)
- {
- return false; // Context must be lost
- }
-
- IDirect3DSurface9 *depthStencil = NULL;
-
+ bool renderTargetChanged = false;
unsigned int renderTargetSerial = framebufferObject->getRenderTargetSerial();
if (renderTargetSerial != mAppliedRenderTargetSerial)
{
- device->SetRenderTarget(0, renderTarget);
+ IDirect3DSurface9 *renderTarget = framebufferObject->getRenderTarget();
+ if (!renderTarget)
+ {
+ return false; // Context must be lost
+ }
+ mDevice->SetRenderTarget(0, renderTarget);
mAppliedRenderTargetSerial = renderTargetSerial;
mScissorStateDirty = true; // Scissor area must be clamped to render target's size-- this is different for different render targets.
+ renderTargetChanged = true;
+ renderTarget->Release();
}
+ IDirect3DSurface9 *depthStencil = NULL;
unsigned int depthbufferSerial = 0;
unsigned int stencilbufferSerial = 0;
if (framebufferObject->getDepthbufferType() != GL_NONE)
@@ -1623,15 +1881,25 @@ bool Context::applyRenderTarget(bool ignoreViewport)
stencilbufferSerial != mAppliedStencilbufferSerial ||
!mDepthStencilInitialized)
{
- device->SetDepthStencilSurface(depthStencil);
+ mDevice->SetDepthStencilSurface(depthStencil);
mAppliedDepthbufferSerial = depthbufferSerial;
mAppliedStencilbufferSerial = stencilbufferSerial;
mDepthStencilInitialized = true;
}
+ if (!mRenderTargetDescInitialized || renderTargetChanged)
+ {
+ IDirect3DSurface9 *renderTarget = framebufferObject->getRenderTarget();
+ if (!renderTarget)
+ {
+ return false; // Context must be lost
+ }
+ renderTarget->GetDesc(&mRenderTargetDesc);
+ mRenderTargetDescInitialized = true;
+ renderTarget->Release();
+ }
+
D3DVIEWPORT9 viewport;
- D3DSURFACE_DESC desc;
- renderTarget->GetDesc(&desc);
float zNear = clamp01(mState.zNear);
float zFar = clamp01(mState.zFar);
@@ -1640,17 +1908,18 @@ bool Context::applyRenderTarget(bool ignoreViewport)
{
viewport.X = 0;
viewport.Y = 0;
- viewport.Width = desc.Width;
- viewport.Height = desc.Height;
+ viewport.Width = mRenderTargetDesc.Width;
+ viewport.Height = mRenderTargetDesc.Height;
viewport.MinZ = 0.0f;
viewport.MaxZ = 1.0f;
}
else
{
- viewport.X = std::max(mState.viewportX, 0);
- viewport.Y = std::max(mState.viewportY, 0);
- viewport.Width = std::min(mState.viewportWidth, (int)desc.Width - (int)viewport.X);
- viewport.Height = std::min(mState.viewportHeight, (int)desc.Height - (int)viewport.Y);
+ RECT rect = transformPixelRect(mState.viewportX, mState.viewportY, mState.viewportWidth, mState.viewportHeight, mRenderTargetDesc.Height);
+ viewport.X = clamp(rect.left, 0L, static_cast<LONG>(mRenderTargetDesc.Width));
+ viewport.Y = clamp(rect.top, 0L, static_cast<LONG>(mRenderTargetDesc.Height));
+ viewport.Width = clamp(rect.right - rect.left, 0L, static_cast<LONG>(mRenderTargetDesc.Width) - static_cast<LONG>(viewport.X));
+ viewport.Height = clamp(rect.bottom - rect.top, 0L, static_cast<LONG>(mRenderTargetDesc.Height) - static_cast<LONG>(viewport.Y));
viewport.MinZ = zNear;
viewport.MaxZ = zFar;
}
@@ -1660,42 +1929,49 @@ bool Context::applyRenderTarget(bool ignoreViewport)
return false; // Nothing to render
}
- device->SetViewport(&viewport);
+ if (renderTargetChanged || !mViewportInitialized || memcmp(&viewport, &mSetViewport, sizeof mSetViewport) != 0)
+ {
+ mDevice->SetViewport(&viewport);
+ mSetViewport = viewport;
+ mViewportInitialized = true;
+ mDxUniformsDirty = true;
+ }
if (mScissorStateDirty)
{
if (mState.scissorTest)
{
- RECT rect = {mState.scissorX,
- mState.scissorY,
- mState.scissorX + mState.scissorWidth,
- mState.scissorY + mState.scissorHeight};
- rect.right = std::min(static_cast<UINT>(rect.right), desc.Width);
- rect.bottom = std::min(static_cast<UINT>(rect.bottom), desc.Height);
- device->SetScissorRect(&rect);
- device->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
+ RECT rect = transformPixelRect(mState.scissorX, mState.scissorY, mState.scissorWidth, mState.scissorHeight, mRenderTargetDesc.Height);
+ rect.left = clamp(rect.left, 0L, static_cast<LONG>(mRenderTargetDesc.Width));
+ rect.top = clamp(rect.top, 0L, static_cast<LONG>(mRenderTargetDesc.Height));
+ rect.right = clamp(rect.right, 0L, static_cast<LONG>(mRenderTargetDesc.Width));
+ rect.bottom = clamp(rect.bottom, 0L, static_cast<LONG>(mRenderTargetDesc.Height));
+ mDevice->SetScissorRect(&rect);
+ mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE);
}
else
{
- device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
}
mScissorStateDirty = false;
}
- if (mState.currentProgram)
+ if (mState.currentProgram && mDxUniformsDirty)
{
Program *programObject = getCurrentProgram();
GLint halfPixelSize = programObject->getDxHalfPixelSizeLocation();
- GLfloat xy[2] = {1.0f / viewport.Width, 1.0f / viewport.Height};
+ GLfloat xy[2] = {1.0f / viewport.Width, -1.0f / viewport.Height};
programObject->setUniform2fv(halfPixelSize, 1, xy);
- GLint viewport = programObject->getDxViewportLocation();
- GLfloat whxy[4] = {mState.viewportWidth / 2.0f, mState.viewportHeight / 2.0f,
+ // These values are used for computing gl_FragCoord in Program::linkVaryings(). The approach depends on Shader Model 3.0 support.
+ GLint coord = programObject->getDxCoordLocation();
+ float h = mSupportsShaderModel3 ? mRenderTargetDesc.Height : mState.viewportHeight / 2.0f;
+ GLfloat whxy[4] = {mState.viewportWidth / 2.0f, h,
(float)mState.viewportX + mState.viewportWidth / 2.0f,
(float)mState.viewportY + mState.viewportHeight / 2.0f};
- programObject->setUniform4fv(viewport, 1, whxy);
+ programObject->setUniform4fv(coord, 1, whxy);
GLint depth = programObject->getDxDepthLocation();
GLfloat dz[2] = {(zFar - zNear) / 2.0f, (zNear + zFar) / 2.0f};
@@ -1704,6 +1980,7 @@ bool Context::applyRenderTarget(bool ignoreViewport)
GLint depthRange = programObject->getDxDepthRangeLocation();
GLfloat nearFarDiff[3] = {zNear, zFar, zFar - zNear};
programObject->setUniform3fv(depthRange, 1, nearFarDiff);
+ mDxUniformsDirty = false;
}
return true;
@@ -1712,28 +1989,37 @@ bool Context::applyRenderTarget(bool ignoreViewport)
// Applies the fixed-function state (culling, depth test, alpha blending, stenciling, etc) to the Direct3D 9 device
void Context::applyState(GLenum drawMode)
{
- IDirect3DDevice9 *device = getDevice();
Program *programObject = getCurrentProgram();
+ Framebuffer *framebufferObject = getDrawFramebuffer();
+
+ GLenum adjustedFrontFace = adjustWinding(mState.frontFace);
+
GLint frontCCW = programObject->getDxFrontCCWLocation();
- GLint ccw = (mState.frontFace == GL_CCW);
+ GLint ccw = (adjustedFrontFace == GL_CCW);
programObject->setUniform1iv(frontCCW, 1, &ccw);
GLint pointsOrLines = programObject->getDxPointsOrLinesLocation();
GLint alwaysFront = !isTriangleMode(drawMode);
programObject->setUniform1iv(pointsOrLines, 1, &alwaysFront);
- Framebuffer *framebufferObject = getDrawFramebuffer();
+ D3DADAPTER_IDENTIFIER9 *identifier = mDisplay->getAdapterIdentifier();
+ bool zeroColorMaskAllowed = identifier->VendorId != 0x1002;
+ // Apparently some ATI cards have a bug where a draw with a zero color
+ // write mask can cause later draws to have incorrect results. Instead,
+ // set a nonzero color write mask but modify the blend state so that no
+ // drawing is done.
+ // http://code.google.com/p/angleproject/issues/detail?id=169
if (mCullStateDirty || mFrontFaceDirty)
{
if (mState.cullFace)
{
- device->SetRenderState(D3DRS_CULLMODE, es2dx::ConvertCullMode(mState.cullMode, mState.frontFace));
+ mDevice->SetRenderState(D3DRS_CULLMODE, es2dx::ConvertCullMode(mState.cullMode, adjustedFrontFace));
}
else
{
- device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+ mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
}
mCullStateDirty = false;
@@ -1741,61 +2027,66 @@ void Context::applyState(GLenum drawMode)
if (mDepthStateDirty)
{
- if (mState.depthTest && framebufferObject->getDepthbufferType() != GL_NONE)
+ if (mState.depthTest)
{
- device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
- device->SetRenderState(D3DRS_ZFUNC, es2dx::ConvertComparison(mState.depthFunc));
+ mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
+ mDevice->SetRenderState(D3DRS_ZFUNC, es2dx::ConvertComparison(mState.depthFunc));
}
else
{
- device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
+ mDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
}
mDepthStateDirty = false;
}
+ if (!zeroColorMaskAllowed && (mMaskStateDirty || mBlendStateDirty))
+ {
+ mBlendStateDirty = true;
+ mMaskStateDirty = true;
+ }
+
if (mBlendStateDirty)
{
if (mState.blend)
{
- device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
+ mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
if (mState.sourceBlendRGB != GL_CONSTANT_ALPHA && mState.sourceBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA &&
mState.destBlendRGB != GL_CONSTANT_ALPHA && mState.destBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA)
{
- device->SetRenderState(D3DRS_BLENDFACTOR, es2dx::ConvertColor(mState.blendColor));
+ mDevice->SetRenderState(D3DRS_BLENDFACTOR, es2dx::ConvertColor(mState.blendColor));
}
else
{
- device->SetRenderState(D3DRS_BLENDFACTOR, D3DCOLOR_RGBA(unorm<8>(mState.blendColor.alpha),
+ mDevice->SetRenderState(D3DRS_BLENDFACTOR, D3DCOLOR_RGBA(unorm<8>(mState.blendColor.alpha),
unorm<8>(mState.blendColor.alpha),
unorm<8>(mState.blendColor.alpha),
unorm<8>(mState.blendColor.alpha)));
}
- device->SetRenderState(D3DRS_SRCBLEND, es2dx::ConvertBlendFunc(mState.sourceBlendRGB));
- device->SetRenderState(D3DRS_DESTBLEND, es2dx::ConvertBlendFunc(mState.destBlendRGB));
- device->SetRenderState(D3DRS_BLENDOP, es2dx::ConvertBlendOp(mState.blendEquationRGB));
+ mDevice->SetRenderState(D3DRS_SRCBLEND, es2dx::ConvertBlendFunc(mState.sourceBlendRGB));
+ mDevice->SetRenderState(D3DRS_DESTBLEND, es2dx::ConvertBlendFunc(mState.destBlendRGB));
+ mDevice->SetRenderState(D3DRS_BLENDOP, es2dx::ConvertBlendOp(mState.blendEquationRGB));
if (mState.sourceBlendRGB != mState.sourceBlendAlpha ||
mState.destBlendRGB != mState.destBlendAlpha ||
mState.blendEquationRGB != mState.blendEquationAlpha)
{
- device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
-
- device->SetRenderState(D3DRS_SRCBLENDALPHA, es2dx::ConvertBlendFunc(mState.sourceBlendAlpha));
- device->SetRenderState(D3DRS_DESTBLENDALPHA, es2dx::ConvertBlendFunc(mState.destBlendAlpha));
- device->SetRenderState(D3DRS_BLENDOPALPHA, es2dx::ConvertBlendOp(mState.blendEquationAlpha));
+ mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
+ mDevice->SetRenderState(D3DRS_SRCBLENDALPHA, es2dx::ConvertBlendFunc(mState.sourceBlendAlpha));
+ mDevice->SetRenderState(D3DRS_DESTBLENDALPHA, es2dx::ConvertBlendFunc(mState.destBlendAlpha));
+ mDevice->SetRenderState(D3DRS_BLENDOPALPHA, es2dx::ConvertBlendOp(mState.blendEquationAlpha));
}
else
{
- device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE);
}
}
else
{
- device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
}
mBlendStateDirty = false;
@@ -1805,8 +2096,8 @@ void Context::applyState(GLenum drawMode)
{
if (mState.stencilTest && framebufferObject->hasStencil())
{
- device->SetRenderState(D3DRS_STENCILENABLE, TRUE);
- device->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE);
+ mDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE);
+ mDevice->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE);
// FIXME: Unsupported by D3D9
const D3DRENDERSTATETYPE D3DRS_CCW_STENCILREF = D3DRS_STENCILREF;
@@ -1821,50 +2112,65 @@ void Context::applyState(GLenum drawMode)
}
// get the maximum size of the stencil ref
- gl::DepthStencilbuffer *stencilbuffer = framebufferObject->getStencilbuffer();
+ gl::Renderbuffer *stencilbuffer = framebufferObject->getStencilbuffer();
GLuint maxStencil = (1 << stencilbuffer->getStencilSize()) - 1;
- device->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, mState.stencilWritemask);
- device->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC,
+ mDevice->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, mState.stencilWritemask);
+ mDevice->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC,
es2dx::ConvertComparison(mState.stencilFunc));
- device->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, (mState.stencilRef < (GLint)maxStencil) ? mState.stencilRef : maxStencil);
- device->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, mState.stencilMask);
+ mDevice->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, (mState.stencilRef < (GLint)maxStencil) ? mState.stencilRef : maxStencil);
+ mDevice->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, mState.stencilMask);
- device->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL,
+ mDevice->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL,
es2dx::ConvertStencilOp(mState.stencilFail));
- device->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL,
+ mDevice->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL,
es2dx::ConvertStencilOp(mState.stencilPassDepthFail));
- device->SetRenderState(mState.frontFace == GL_CCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS,
+ mDevice->SetRenderState(adjustedFrontFace == GL_CCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS,
es2dx::ConvertStencilOp(mState.stencilPassDepthPass));
- device->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, mState.stencilBackWritemask);
- device->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC,
+ mDevice->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, mState.stencilBackWritemask);
+ mDevice->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC,
es2dx::ConvertComparison(mState.stencilBackFunc));
- device->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, (mState.stencilBackRef < (GLint)maxStencil) ? mState.stencilBackRef : maxStencil);
- device->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, mState.stencilBackMask);
+ mDevice->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, (mState.stencilBackRef < (GLint)maxStencil) ? mState.stencilBackRef : maxStencil);
+ mDevice->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, mState.stencilBackMask);
- device->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL,
+ mDevice->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL,
es2dx::ConvertStencilOp(mState.stencilBackFail));
- device->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL,
+ mDevice->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL,
es2dx::ConvertStencilOp(mState.stencilBackPassDepthFail));
- device->SetRenderState(mState.frontFace == GL_CW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS,
+ mDevice->SetRenderState(adjustedFrontFace == GL_CW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS,
es2dx::ConvertStencilOp(mState.stencilBackPassDepthPass));
}
else
{
- device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
}
mStencilStateDirty = false;
+ mFrontFaceDirty = false;
}
if (mMaskStateDirty)
{
- device->SetRenderState(D3DRS_COLORWRITEENABLE, es2dx::ConvertColorMask(mState.colorMaskRed, mState.colorMaskGreen,
- mState.colorMaskBlue, mState.colorMaskAlpha));
- device->SetRenderState(D3DRS_ZWRITEENABLE, mState.depthMask ? TRUE : FALSE);
+ int colorMask = es2dx::ConvertColorMask(mState.colorMaskRed, mState.colorMaskGreen,
+ mState.colorMaskBlue, mState.colorMaskAlpha);
+ if (colorMask == 0 && !zeroColorMaskAllowed)
+ {
+ // Enable green channel, but set blending so nothing will be drawn.
+ mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_GREEN);
+ mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
+
+ mDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
+ mDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
+ mDevice->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
+ }
+ else
+ {
+ mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, colorMask);
+ }
+ mDevice->SetRenderState(D3DRS_ZWRITEENABLE, mState.depthMask ? TRUE : FALSE);
mMaskStateDirty = false;
}
@@ -1873,18 +2179,18 @@ void Context::applyState(GLenum drawMode)
{
if (mState.polygonOffsetFill)
{
- gl::DepthStencilbuffer *depthbuffer = framebufferObject->getDepthbuffer();
+ gl::Renderbuffer *depthbuffer = framebufferObject->getDepthbuffer();
if (depthbuffer)
{
- device->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *((DWORD*)&mState.polygonOffsetFactor));
+ mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *((DWORD*)&mState.polygonOffsetFactor));
float depthBias = ldexp(mState.polygonOffsetUnits, -(int)(depthbuffer->getDepthSize()));
- device->SetRenderState(D3DRS_DEPTHBIAS, *((DWORD*)&depthBias));
+ mDevice->SetRenderState(D3DRS_DEPTHBIAS, *((DWORD*)&depthBias));
}
}
else
{
- device->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, 0);
- device->SetRenderState(D3DRS_DEPTHBIAS, 0);
+ mDevice->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, 0);
+ mDevice->SetRenderState(D3DRS_DEPTHBIAS, 0);
}
mPolygonOffsetStateDirty = false;
@@ -1892,48 +2198,41 @@ void Context::applyState(GLenum drawMode)
if (mSampleStateDirty)
{
- if (framebufferObject->isMultisample())
+ if (mState.sampleAlphaToCoverage)
{
- if (mState.sampleAlphaToCoverage)
- {
- FIXME("Sample alpha to coverage is unimplemented.");
- }
+ FIXME("Sample alpha to coverage is unimplemented.");
+ }
- device->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE);
- if (mState.sampleCoverage)
+ mDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE);
+ if (mState.sampleCoverage)
+ {
+ unsigned int mask = 0;
+ if (mState.sampleCoverageValue != 0)
{
- unsigned int mask = 0;
- if (mState.sampleCoverageValue != 0)
+ float threshold = 0.5f;
+
+ for (int i = 0; i < framebufferObject->getSamples(); ++i)
{
- float threshold = 0.5f;
+ mask <<= 1;
- for (int i = 0; i < framebufferObject->getSamples(); ++i)
+ if ((i + 1) * mState.sampleCoverageValue >= threshold)
{
- mask <<= 1;
-
- if ((i + 1) * mState.sampleCoverageValue >= threshold)
- {
- threshold += 1.0f;
- mask |= 1;
- }
+ threshold += 1.0f;
+ mask |= 1;
}
}
-
- if (mState.sampleCoverageInvert)
- {
- mask = ~mask;
- }
-
- device->SetRenderState(D3DRS_MULTISAMPLEMASK, mask);
}
- else
+
+ if (mState.sampleCoverageInvert)
{
- device->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF);
+ mask = ~mask;
}
+
+ mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, mask);
}
else
{
- device->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, FALSE);
+ mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF);
}
mSampleStateDirty = false;
@@ -1941,52 +2240,37 @@ void Context::applyState(GLenum drawMode)
if (mDitherStateDirty)
{
- device->SetRenderState(D3DRS_DITHERENABLE, mState.dither ? TRUE : FALSE);
+ mDevice->SetRenderState(D3DRS_DITHERENABLE, mState.dither ? TRUE : FALSE);
mDitherStateDirty = false;
}
-
- mFrontFaceDirty = false;
}
-// Fill in the semanticIndex field of the array of TranslatedAttributes based on the active GLSL program.
-void Context::lookupAttributeMapping(TranslatedAttribute *attributes)
+GLenum Context::applyVertexBuffer(GLint first, GLsizei count, GLsizei instances, GLsizei *repeatDraw)
{
- for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
- {
- if (attributes[i].active)
- {
- attributes[i].semanticIndex = getCurrentProgram()->getSemanticIndex(i);
- }
- }
-}
+ TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS];
-GLenum Context::applyVertexBuffer(GLint first, GLsizei count)
-{
- TranslatedAttribute translated[MAX_VERTEX_ATTRIBS];
-
- GLenum err = mVertexDataManager->prepareVertexData(first, count, translated);
+ GLenum err = mVertexDataManager->prepareVertexData(first, count, attributes, instances);
if (err != GL_NO_ERROR)
{
return err;
}
- lookupAttributeMapping(translated);
-
- mVertexDataManager->setupAttributes(translated);
-
- return GL_NO_ERROR;
+ return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, getCurrentProgram(), instances, repeatDraw);
}
// Applies the indices and element array bindings to the Direct3D 9 device
-GLenum Context::applyIndexBuffer(const void *indices, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo)
+GLenum Context::applyIndexBuffer(const GLvoid *indices, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo)
{
- IDirect3DDevice9 *device = getDevice();
GLenum err = mIndexDataManager->prepareIndexData(type, count, mState.elementArrayBuffer.get(), indices, indexInfo);
if (err == GL_NO_ERROR)
{
- device->SetIndices(indexInfo->indexBuffer);
+ if (indexInfo->serial != mAppliedIBSerial)
+ {
+ mDevice->SetIndices(indexInfo->indexBuffer);
+ mAppliedIBSerial = indexInfo->serial;
+ }
}
return err;
@@ -1995,19 +2279,16 @@ GLenum Context::applyIndexBuffer(const void *indices, GLsizei count, GLenum mode
// Applies the shaders and shader constants to the Direct3D 9 device
void Context::applyShaders()
{
- IDirect3DDevice9 *device = getDevice();
Program *programObject = getCurrentProgram();
- IDirect3DVertexShader9 *vertexShader = programObject->getVertexShader();
- IDirect3DPixelShader9 *pixelShader = programObject->getPixelShader();
-
- device->SetVertexShader(vertexShader);
- device->SetPixelShader(pixelShader);
-
- if (programObject->getSerial() != mAppliedProgram)
+ if (programObject->getSerial() != mAppliedProgramSerial)
{
+ IDirect3DVertexShader9 *vertexShader = programObject->getVertexShader();
+ IDirect3DPixelShader9 *pixelShader = programObject->getPixelShader();
+
+ mDevice->SetPixelShader(pixelShader);
+ mDevice->SetVertexShader(vertexShader);
programObject->dirtyAllUniforms();
- programObject->dirtyAllSamplers();
- mAppliedProgram = programObject->getSerial();
+ mAppliedProgramSerial = programObject->getSerial();
}
programObject->applyUniforms();
@@ -2016,58 +2297,96 @@ void Context::applyShaders()
// Applies the textures and sampler states to the Direct3D 9 device
void Context::applyTextures()
{
- IDirect3DDevice9 *device = getDevice();
+ applyTextures(SAMPLER_PIXEL);
+
+ if (mSupportsVertexTexture)
+ {
+ applyTextures(SAMPLER_VERTEX);
+ }
+}
+
+// For each Direct3D 9 sampler of either the pixel or vertex stage,
+// looks up the corresponding OpenGL texture image unit and texture type,
+// and sets the texture and its addressing/filtering state (or NULL when inactive).
+void Context::applyTextures(SamplerType type)
+{
Program *programObject = getCurrentProgram();
- for (int sampler = 0; sampler < MAX_TEXTURE_IMAGE_UNITS; sampler++)
+ int samplerCount = (type == SAMPLER_PIXEL) ? MAX_TEXTURE_IMAGE_UNITS : MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; // Range of Direct3D 9 samplers of given sampler type
+ unsigned int *appliedTextureSerial = (type == SAMPLER_PIXEL) ? mAppliedTextureSerialPS : mAppliedTextureSerialVS;
+ int d3dSamplerOffset = (type == SAMPLER_PIXEL) ? 0 : D3DVERTEXTEXTURESAMPLER0;
+ int samplerRange = programObject->getUsedSamplerRange(type);
+
+ for (int samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++)
{
- int textureUnit = programObject->getSamplerMapping(sampler);
+ int textureUnit = programObject->getSamplerMapping(type, samplerIndex); // OpenGL texture image unit index
+ int d3dSampler = samplerIndex + d3dSamplerOffset;
+
if (textureUnit != -1)
{
- SamplerType textureType = programObject->getSamplerType(sampler);
+ TextureType textureType = programObject->getSamplerTextureType(type, samplerIndex);
Texture *texture = getSamplerTexture(textureUnit, textureType);
- if (programObject->isSamplerDirty(sampler) || texture->isDirty())
+ if (appliedTextureSerial[samplerIndex] != texture->getTextureSerial() || texture->hasDirtyParameters() || texture->hasDirtyImages())
{
- if (texture->isComplete())
- {
- GLenum wrapS = texture->getWrapS();
- GLenum wrapT = texture->getWrapT();
- GLenum minFilter = texture->getMinFilter();
- GLenum magFilter = texture->getMagFilter();
-
- device->SetSamplerState(sampler, D3DSAMP_ADDRESSU, es2dx::ConvertTextureWrap(wrapS));
- device->SetSamplerState(sampler, D3DSAMP_ADDRESSV, es2dx::ConvertTextureWrap(wrapT));
+ IDirect3DBaseTexture9 *d3dTexture = texture->getTexture();
- device->SetSamplerState(sampler, D3DSAMP_MAGFILTER, es2dx::ConvertMagFilter(magFilter));
- D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter;
- es2dx::ConvertMinFilter(minFilter, &d3dMinFilter, &d3dMipFilter);
- device->SetSamplerState(sampler, D3DSAMP_MINFILTER, d3dMinFilter);
- device->SetSamplerState(sampler, D3DSAMP_MIPFILTER, d3dMipFilter);
+ if (d3dTexture)
+ {
+ if (appliedTextureSerial[samplerIndex] != texture->getTextureSerial() || texture->hasDirtyParameters())
+ {
+ GLenum wrapS = texture->getWrapS();
+ GLenum wrapT = texture->getWrapT();
+ GLenum minFilter = texture->getMinFilter();
+ GLenum magFilter = texture->getMagFilter();
+
+ mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSU, es2dx::ConvertTextureWrap(wrapS));
+ mDevice->SetSamplerState(d3dSampler, D3DSAMP_ADDRESSV, es2dx::ConvertTextureWrap(wrapT));
+
+ mDevice->SetSamplerState(d3dSampler, D3DSAMP_MAGFILTER, es2dx::ConvertMagFilter(magFilter));
+ D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter;
+ es2dx::ConvertMinFilter(minFilter, &d3dMinFilter, &d3dMipFilter);
+ mDevice->SetSamplerState(d3dSampler, D3DSAMP_MINFILTER, d3dMinFilter);
+ mDevice->SetSamplerState(d3dSampler, D3DSAMP_MIPFILTER, d3dMipFilter);
+ }
- device->SetTexture(sampler, texture->getTexture());
+ if (appliedTextureSerial[samplerIndex] != texture->getTextureSerial() || texture->hasDirtyImages())
+ {
+ mDevice->SetTexture(d3dSampler, d3dTexture);
+ }
}
else
{
- device->SetTexture(sampler, getIncompleteTexture(textureType)->getTexture());
+ mDevice->SetTexture(d3dSampler, getIncompleteTexture(textureType)->getTexture());
}
- }
- programObject->setSamplerDirty(sampler, false);
+ appliedTextureSerial[samplerIndex] = texture->getTextureSerial();
+ texture->resetDirty();
+ }
}
else
{
- if (programObject->isSamplerDirty(sampler))
+ if (appliedTextureSerial[samplerIndex] != 0)
{
- device->SetTexture(sampler, NULL);
- programObject->setSamplerDirty(sampler, false);
+ mDevice->SetTexture(d3dSampler, NULL);
+ appliedTextureSerial[samplerIndex] = 0;
}
- }
+ }
+ }
+
+ for (int samplerIndex = samplerRange; samplerIndex < samplerCount; samplerIndex++)
+ {
+ if (appliedTextureSerial[samplerIndex] != 0)
+ {
+ mDevice->SetTexture(samplerIndex + d3dSamplerOffset, NULL);
+ appliedTextureSerial[samplerIndex] = 0;
+ }
}
}
-void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels)
+void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, GLsizei *bufSize, void* pixels)
{
Framebuffer *framebuffer = getReadFramebuffer();
@@ -2081,55 +2400,93 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
return error(GL_INVALID_OPERATION);
}
- IDirect3DSurface9 *renderTarget = framebuffer->getRenderTarget();
+ GLsizei outputPitch = ComputePitch(width, format, type, mState.packAlignment);
+ // sized query sanity check
+ if (bufSize)
+ {
+ int requiredSize = outputPitch * height;
+ if (requiredSize > *bufSize)
+ {
+ return error(GL_INVALID_OPERATION);
+ }
+ }
+ IDirect3DSurface9 *renderTarget = framebuffer->getRenderTarget();
if (!renderTarget)
{
return; // Context must be lost, return silently
}
- IDirect3DDevice9 *device = getDevice();
-
D3DSURFACE_DESC desc;
renderTarget->GetDesc(&desc);
- IDirect3DSurface9 *systemSurface;
- HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &systemSurface, NULL);
-
- if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
+ if (desc.MultiSampleType != D3DMULTISAMPLE_NONE)
{
+ UNIMPLEMENTED(); // FIXME: Requires resolve using StretchRect into non-multisampled render target
+ renderTarget->Release();
return error(GL_OUT_OF_MEMORY);
}
- ASSERT(SUCCEEDED(result));
+ HRESULT result;
+ IDirect3DSurface9 *systemSurface = NULL;
+ bool directToPixels = getPackReverseRowOrder() && getPackAlignment() <= 4 && mDisplay->isD3d9ExDevice() &&
+ x == 0 && y == 0 && UINT(width) == desc.Width && UINT(height) == desc.Height &&
+ desc.Format == D3DFMT_A8R8G8B8 && format == GL_BGRA_EXT && type == GL_UNSIGNED_BYTE;
+ if (directToPixels)
+ {
+ // Use the pixels ptr as a shared handle to write directly into client's memory
+ result = mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format,
+ D3DPOOL_SYSTEMMEM, &systemSurface, &pixels);
+ if (FAILED(result))
+ {
+ // Try again without the shared handle
+ directToPixels = false;
+ }
+ }
- if (desc.MultiSampleType != D3DMULTISAMPLE_NONE)
+ if (!directToPixels)
{
- UNIMPLEMENTED(); // FIXME: Requires resolve using StretchRect into non-multisampled render target
+ result = mDevice->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format,
+ D3DPOOL_SYSTEMMEM, &systemSurface, NULL);
+ if (FAILED(result))
+ {
+ ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
+ return error(GL_OUT_OF_MEMORY);
+ }
}
- result = device->GetRenderTargetData(renderTarget, systemSurface);
+ result = mDevice->GetRenderTargetData(renderTarget, systemSurface);
+ renderTarget->Release();
+ renderTarget = NULL;
if (FAILED(result))
{
systemSurface->Release();
- switch (result)
+ // It turns out that D3D will sometimes produce more error
+ // codes than those documented.
+ if (checkDeviceLost(result))
+ return error(GL_OUT_OF_MEMORY);
+ else
{
- case D3DERR_DRIVERINTERNALERROR:
- case D3DERR_DEVICELOST:
- return error(GL_OUT_OF_MEMORY);
- default:
- UNREACHABLE();
- return; // No sensible error to generate
+ UNREACHABLE();
+ return;
}
+
+ }
+
+ if (directToPixels)
+ {
+ systemSurface->Release();
+ return;
}
D3DLOCKED_RECT lock;
- RECT rect = {std::max(x, 0),
- std::max(y, 0),
- std::min(x + width, (int)desc.Width),
- std::min(y + height, (int)desc.Height)};
+ RECT rect = transformPixelRect(x, y, width, height, desc.Height);
+ rect.left = clamp(rect.left, 0L, static_cast<LONG>(desc.Width));
+ rect.top = clamp(rect.top, 0L, static_cast<LONG>(desc.Height));
+ rect.right = clamp(rect.right, 0L, static_cast<LONG>(desc.Width));
+ rect.bottom = clamp(rect.bottom, 0L, static_cast<LONG>(desc.Height));
result = systemSurface->LockRect(&lock, &rect, D3DLOCK_READONLY);
@@ -2141,11 +2498,21 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
return; // No sensible error to generate
}
- unsigned char *source = (unsigned char*)lock.pBits;
unsigned char *dest = (unsigned char*)pixels;
unsigned short *dest16 = (unsigned short*)pixels;
- GLsizei outputPitch = ComputePitch(width, format, type, mState.packAlignment);
+ unsigned char *source;
+ int inputPitch;
+ if (getPackReverseRowOrder())
+ {
+ source = (unsigned char*)lock.pBits;
+ inputPitch = lock.Pitch;
+ }
+ else
+ {
+ source = ((unsigned char*)lock.pBits) + lock.Pitch * (rect.bottom - rect.top - 1);
+ inputPitch = -lock.Pitch;
+ }
for (int j = 0; j < rect.bottom - rect.top; j++)
{
@@ -2157,7 +2524,7 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
// an RGBA source buffer. Note that buffers with no
// alpha go through the slow path below.
memcpy(dest + j * outputPitch,
- source + j * lock.Pitch,
+ source + j * inputPitch,
(rect.right - rect.left) * 4);
continue;
}
@@ -2173,7 +2540,7 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
{
case D3DFMT_R5G6B5:
{
- unsigned short rgb = *(unsigned short*)(source + 2 * i + j * lock.Pitch);
+ unsigned short rgb = *(unsigned short*)(source + 2 * i + j * inputPitch);
a = 1.0f;
b = (rgb & 0x001F) * (1.0f / 0x001F);
@@ -2183,7 +2550,7 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
break;
case D3DFMT_A1R5G5B5:
{
- unsigned short argb = *(unsigned short*)(source + 2 * i + j * lock.Pitch);
+ unsigned short argb = *(unsigned short*)(source + 2 * i + j * inputPitch);
a = (argb & 0x8000) ? 1.0f : 0.0f;
b = (argb & 0x001F) * (1.0f / 0x001F);
@@ -2193,7 +2560,7 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
break;
case D3DFMT_A8R8G8B8:
{
- unsigned int argb = *(unsigned int*)(source + 4 * i + j * lock.Pitch);
+ unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch);
a = (argb & 0xFF000000) * (1.0f / 0xFF000000);
b = (argb & 0x000000FF) * (1.0f / 0x000000FF);
@@ -2203,7 +2570,7 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
break;
case D3DFMT_X8R8G8B8:
{
- unsigned int xrgb = *(unsigned int*)(source + 4 * i + j * lock.Pitch);
+ unsigned int xrgb = *(unsigned int*)(source + 4 * i + j * inputPitch);
a = 1.0f;
b = (xrgb & 0x000000FF) * (1.0f / 0x000000FF);
@@ -2213,7 +2580,7 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
break;
case D3DFMT_A2R10G10B10:
{
- unsigned int argb = *(unsigned int*)(source + 4 * i + j * lock.Pitch);
+ unsigned int argb = *(unsigned int*)(source + 4 * i + j * inputPitch);
a = (argb & 0xC0000000) * (1.0f / 0xC0000000);
b = (argb & 0x000003FF) * (1.0f / 0x000003FF);
@@ -2224,10 +2591,10 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
case D3DFMT_A32B32G32R32F:
{
// float formats in D3D are stored rgba, rather than the other way round
- r = *((float*)(source + 16 * i + j * lock.Pitch) + 0);
- g = *((float*)(source + 16 * i + j * lock.Pitch) + 1);
- b = *((float*)(source + 16 * i + j * lock.Pitch) + 2);
- a = *((float*)(source + 16 * i + j * lock.Pitch) + 3);
+ r = *((float*)(source + 16 * i + j * inputPitch) + 0);
+ g = *((float*)(source + 16 * i + j * inputPitch) + 1);
+ b = *((float*)(source + 16 * i + j * inputPitch) + 2);
+ a = *((float*)(source + 16 * i + j * inputPitch) + 3);
}
break;
case D3DFMT_A16B16G16R16F:
@@ -2235,7 +2602,7 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
// float formats in D3D are stored rgba, rather than the other way round
float abgr[4];
- D3DXFloat16To32Array(abgr, (D3DXFLOAT16*)(source + 8 * i + j * lock.Pitch), 4);
+ D3DXFloat16To32Array(abgr, (D3DXFLOAT16*)(source + 8 * i + j * inputPitch), 4);
a = abgr[3];
b = abgr[2];
@@ -2246,6 +2613,7 @@ void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum
default:
UNIMPLEMENTED(); // FIXME
UNREACHABLE();
+ return;
}
switch (format)
@@ -2330,13 +2698,9 @@ void Context::clear(GLbitfield mask)
if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE)
{
- error(GL_INVALID_FRAMEBUFFER_OPERATION);
-
- return;
+ return error(GL_INVALID_FRAMEBUFFER_OPERATION);
}
- egl::Display *display = getDisplay();
- IDirect3DDevice9 *device = getDevice();
DWORD flags = 0;
if (mask & GL_COLOR_BUFFER_BIT)
@@ -2375,7 +2739,7 @@ void Context::clear(GLbitfield mask)
D3DSURFACE_DESC desc;
depthStencil->GetDesc(&desc);
- unsigned int stencilSize = es2dx::GetStencilSize(desc.Format);
+ unsigned int stencilSize = dx2es::GetStencilSize(desc.Format);
stencilUnmasked = (0x1 << stencilSize) - 1;
if (stencilUnmasked != 0x0)
@@ -2396,23 +2760,13 @@ void Context::clear(GLbitfield mask)
}
D3DCOLOR color = D3DCOLOR_ARGB(unorm<8>(mState.colorClearValue.alpha),
- unorm<8>(mState.colorClearValue.red),
- unorm<8>(mState.colorClearValue.green),
- unorm<8>(mState.colorClearValue.blue));
+ unorm<8>(mState.colorClearValue.red),
+ unorm<8>(mState.colorClearValue.green),
+ unorm<8>(mState.colorClearValue.blue));
float depth = clamp01(mState.depthClearValue);
int stencil = mState.stencilClearValue & 0x000000FF;
- IDirect3DSurface9 *renderTarget = framebufferObject->getRenderTarget();
-
- if (!renderTarget)
- {
- return; // Context must be lost, return silently
- }
-
- D3DSURFACE_DESC desc;
- renderTarget->GetDesc(&desc);
-
- bool alphaUnmasked = (es2dx::GetAlphaSize(desc.Format) == 0) || mState.colorMaskAlpha;
+ bool alphaUnmasked = (dx2es::GetAlphaSize(mRenderTargetDesc.Format) == 0) || mState.colorMaskAlpha;
const bool needMaskedStencilClear = (flags & D3DCLEAR_STENCIL) &&
(mState.stencilWritemask & stencilUnmasked) != stencilUnmasked;
@@ -2428,25 +2782,37 @@ void Context::clear(GLbitfield mask)
HRESULT hr;
if (mMaskedClearSavedState == NULL)
{
- hr = device->BeginStateBlock();
+ hr = mDevice->BeginStateBlock();
ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
- device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
- device->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
- device->SetRenderState(D3DRS_ZENABLE, FALSE);
- device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
- device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
- device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
- device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
- device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
- device->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
- device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
- device->SetPixelShader(NULL);
- device->SetVertexShader(NULL);
- device->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
- device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE);
-
- hr = device->EndStateBlock(&mMaskedClearSavedState);
+ mDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
+ mDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+ mDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
+ mDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
+ mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
+ mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
+ mDevice->SetPixelShader(NULL);
+ mDevice->SetVertexShader(NULL);
+ mDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
+ mDevice->SetStreamSource(0, NULL, 0, 0);
+ mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
+ mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
+ mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR);
+ mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
+ mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR);
+ mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color);
+ mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF);
+
+ for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ mDevice->SetStreamSourceFreq(i, 1);
+ }
+
+ hr = mDevice->EndStateBlock(&mMaskedClearSavedState);
ASSERT(SUCCEEDED(hr) || hr == D3DERR_OUTOFVIDEOMEMORY || hr == E_OUTOFMEMORY);
}
@@ -2458,88 +2824,86 @@ void Context::clear(GLbitfield mask)
ASSERT(SUCCEEDED(hr));
}
- device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
- device->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
- device->SetRenderState(D3DRS_ZENABLE, FALSE);
- device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
- device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
- device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
- device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
- device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
+ mDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS);
+ mDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
+ mDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
+ mDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, 0);
if (flags & D3DCLEAR_TARGET)
{
- device->SetRenderState(D3DRS_COLORWRITEENABLE, (mState.colorMaskRed ? D3DCOLORWRITEENABLE_RED : 0) |
- (mState.colorMaskGreen ? D3DCOLORWRITEENABLE_GREEN : 0) |
- (mState.colorMaskBlue ? D3DCOLORWRITEENABLE_BLUE : 0) |
- (mState.colorMaskAlpha ? D3DCOLORWRITEENABLE_ALPHA : 0));
+ mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, es2dx::ConvertColorMask(mState.colorMaskRed, mState.colorMaskGreen, mState.colorMaskBlue, mState.colorMaskAlpha));
}
else
{
- device->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
+ mDevice->SetRenderState(D3DRS_COLORWRITEENABLE, 0);
}
if (stencilUnmasked != 0x0 && (flags & D3DCLEAR_STENCIL))
{
- device->SetRenderState(D3DRS_STENCILENABLE, TRUE);
- device->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
- device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);
- device->SetRenderState(D3DRS_STENCILREF, stencil);
- device->SetRenderState(D3DRS_STENCILWRITEMASK, mState.stencilWritemask);
- device->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE);
- device->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_REPLACE);
- device->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE);
+ mDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE);
+ mDevice->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
+ mDevice->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS);
+ mDevice->SetRenderState(D3DRS_STENCILREF, stencil);
+ mDevice->SetRenderState(D3DRS_STENCILWRITEMASK, mState.stencilWritemask);
+ mDevice->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE);
+ mDevice->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_REPLACE);
+ mDevice->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE);
mStencilStateDirty = true;
}
else
{
- device->SetRenderState(D3DRS_STENCILENABLE, FALSE);
+ mDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
}
- device->SetPixelShader(NULL);
- device->SetVertexShader(NULL);
- device->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
- device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE);
-
- struct Vertex
+ mDevice->SetPixelShader(NULL);
+ mDevice->SetVertexShader(NULL);
+ mDevice->SetFVF(D3DFVF_XYZRHW);
+ mDevice->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
+ mDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
+ mDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TFACTOR);
+ mDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
+ mDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TFACTOR);
+ mDevice->SetRenderState(D3DRS_TEXTUREFACTOR, color);
+ mDevice->SetRenderState(D3DRS_MULTISAMPLEMASK, 0xFFFFFFFF);
+
+ for(int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
{
- float x, y, z, w;
- D3DCOLOR diffuse;
- };
+ mDevice->SetStreamSourceFreq(i, 1);
+ }
+
+ float quad[4][4]; // A quadrilateral covering the target, aligned to match the edges
+ quad[0][0] = -0.5f;
+ quad[0][1] = mRenderTargetDesc.Height - 0.5f;
+ quad[0][2] = 0.0f;
+ quad[0][3] = 1.0f;
+
+ quad[1][0] = mRenderTargetDesc.Width - 0.5f;
+ quad[1][1] = mRenderTargetDesc.Height - 0.5f;
+ quad[1][2] = 0.0f;
+ quad[1][3] = 1.0f;
+
+ quad[2][0] = -0.5f;
+ quad[2][1] = -0.5f;
+ quad[2][2] = 0.0f;
+ quad[2][3] = 1.0f;
- Vertex quad[4];
- quad[0].x = 0.0f;
- quad[0].y = (float)desc.Height;
- quad[0].z = 0.0f;
- quad[0].w = 1.0f;
- quad[0].diffuse = color;
-
- quad[1].x = (float)desc.Width;
- quad[1].y = (float)desc.Height;
- quad[1].z = 0.0f;
- quad[1].w = 1.0f;
- quad[1].diffuse = color;
-
- quad[2].x = 0.0f;
- quad[2].y = 0.0f;
- quad[2].z = 0.0f;
- quad[2].w = 1.0f;
- quad[2].diffuse = color;
-
- quad[3].x = (float)desc.Width;
- quad[3].y = 0.0f;
- quad[3].z = 0.0f;
- quad[3].w = 1.0f;
- quad[3].diffuse = color;
-
- display->startScene();
- device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(Vertex));
+ quad[3][0] = mRenderTargetDesc.Width - 0.5f;
+ quad[3][1] = -0.5f;
+ quad[3][2] = 0.0f;
+ quad[3][3] = 1.0f;
+
+ mDisplay->startScene();
+ mDevice->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(float[4]));
if (flags & D3DCLEAR_ZBUFFER)
{
- device->SetRenderState(D3DRS_ZENABLE, TRUE);
- device->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
- device->Clear(0, NULL, D3DCLEAR_ZBUFFER, color, depth, stencil);
+ mDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
+ mDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
+ mDevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, color, depth, stencil);
}
if (mMaskedClearSavedState != NULL)
@@ -2549,19 +2913,17 @@ void Context::clear(GLbitfield mask)
}
else if (flags)
{
- device->Clear(0, NULL, flags, color, depth, stencil);
+ mDevice->Clear(0, NULL, flags, color, depth, stencil);
}
}
-void Context::drawArrays(GLenum mode, GLint first, GLsizei count)
+void Context::drawArrays(GLenum mode, GLint first, GLsizei count, GLsizei instances)
{
if (!mState.currentProgram)
{
return error(GL_INVALID_OPERATION);
}
- egl::Display *display = getDisplay();
- IDirect3DDevice9 *device = getDevice();
D3DPRIMITIVETYPE primitiveType;
int primitiveCount;
@@ -2580,7 +2942,8 @@ void Context::drawArrays(GLenum mode, GLint first, GLsizei count)
applyState(mode);
- GLenum err = applyVertexBuffer(first, count);
+ GLsizei repeatDraw = 1;
+ GLenum err = applyVertexBuffer(first, count, instances, &repeatDraw);
if (err != GL_NO_ERROR)
{
return error(err);
@@ -2589,25 +2952,49 @@ void Context::drawArrays(GLenum mode, GLint first, GLsizei count)
applyShaders();
applyTextures();
- if (!getCurrentProgram()->validateSamplers())
+ if (!getCurrentProgram()->validateSamplers(false))
{
return error(GL_INVALID_OPERATION);
}
if (!cullSkipsDraw(mode))
{
- display->startScene();
+ mDisplay->startScene();
- device->DrawPrimitive(primitiveType, 0, primitiveCount);
+ if (mode == GL_LINE_LOOP)
+ {
+ drawLineLoop(count, GL_NONE, NULL, 0);
+ }
+ else if (instances > 0)
+ {
+ StaticIndexBuffer *countingIB = mIndexDataManager->getCountingIndices(count);
+ if (countingIB)
+ {
+ if (mAppliedIBSerial != countingIB->getSerial())
+ {
+ mDevice->SetIndices(countingIB->getBuffer());
+ mAppliedIBSerial = countingIB->getSerial();
+ }
- if (mode == GL_LINE_LOOP) // Draw the last segment separately
+ for (int i = 0; i < repeatDraw; i++)
+ {
+ mDevice->DrawIndexedPrimitive(primitiveType, 0, 0, count, 0, primitiveCount);
+ }
+ }
+ else
+ {
+ ERR("Could not create a counting index buffer for glDrawArraysInstanced.");
+ return error(GL_OUT_OF_MEMORY);
+ }
+ }
+ else // Regular case
{
- drawClosingLine(first, first + count - 1);
+ mDevice->DrawPrimitive(primitiveType, 0, primitiveCount);
}
}
}
-void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const void *indices)
+void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei instances)
{
if (!mState.currentProgram)
{
@@ -2619,8 +3006,6 @@ void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const void *
return error(GL_INVALID_OPERATION);
}
- egl::Display *display = getDisplay();
- IDirect3DDevice9 *device = getDevice();
D3DPRIMITIVETYPE primitiveType;
int primitiveCount;
@@ -2647,7 +3032,8 @@ void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const void *
}
GLsizei vertexCount = indexInfo.maxIndex - indexInfo.minIndex + 1;
- err = applyVertexBuffer(indexInfo.minIndex, vertexCount);
+ GLsizei repeatDraw = 1;
+ err = applyVertexBuffer(indexInfo.minIndex, vertexCount, instances, &repeatDraw);
if (err != GL_NO_ERROR)
{
return error(err);
@@ -2656,188 +3042,178 @@ void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const void *
applyShaders();
applyTextures();
- if (!getCurrentProgram()->validateSamplers())
+ if (!getCurrentProgram()->validateSamplers(false))
{
return error(GL_INVALID_OPERATION);
}
if (!cullSkipsDraw(mode))
{
- display->startScene();
-
- device->DrawIndexedPrimitive(primitiveType, -(INT)indexInfo.minIndex, indexInfo.minIndex, vertexCount, indexInfo.startIndex, primitiveCount);
-
- if (mode == GL_LINE_LOOP) // Draw the last segment separately
- {
- drawClosingLine(count, type, indices);
- }
- }
-}
-
-void Context::finish()
-{
- egl::Display *display = getDisplay();
- IDirect3DDevice9 *device = getDevice();
- IDirect3DQuery9 *occlusionQuery = NULL;
-
- HRESULT result = device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery);
-
- if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
- {
- return error(GL_OUT_OF_MEMORY);
- }
-
- ASSERT(SUCCEEDED(result));
-
- if (occlusionQuery)
- {
- IDirect3DStateBlock9 *savedState = NULL;
- device->CreateStateBlock(D3DSBT_ALL, &savedState);
-
- HRESULT result = occlusionQuery->Issue(D3DISSUE_BEGIN);
- ASSERT(SUCCEEDED(result));
-
- // Render something outside the render target
- device->SetPixelShader(NULL);
- device->SetVertexShader(NULL);
- device->SetFVF(D3DFVF_XYZRHW);
- float data[4] = {-1.0f, -1.0f, -1.0f, 1.0f};
- display->startScene();
- device->DrawPrimitiveUP(D3DPT_POINTLIST, 1, data, sizeof(data));
-
- result = occlusionQuery->Issue(D3DISSUE_END);
- ASSERT(SUCCEEDED(result));
+ mDisplay->startScene();
- while (occlusionQuery->GetData(NULL, 0, D3DGETDATA_FLUSH) == S_FALSE)
+ if (mode == GL_LINE_LOOP)
{
- // Keep polling, but allow other threads to do something useful first
- Sleep(0);
+ drawLineLoop(count, type, indices, indexInfo.minIndex);
}
-
- occlusionQuery->Release();
-
- if (savedState)
+ else
{
- savedState->Apply();
- savedState->Release();
+ for (int i = 0; i < repeatDraw; i++)
+ {
+ mDevice->DrawIndexedPrimitive(primitiveType, -(INT)indexInfo.minIndex, indexInfo.minIndex, vertexCount, indexInfo.startIndex, primitiveCount);
+ }
}
}
}
-void Context::flush()
+// Implements glFlush when block is false, glFinish when block is true
+void Context::sync(bool block)
{
- IDirect3DDevice9 *device = getDevice();
- IDirect3DQuery9 *eventQuery = NULL;
-
- HRESULT result = device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery);
+ mDisplay->sync(block);
+}
- if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
+void Context::drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex)
+{
+ // Get the raw indices for an indexed draw
+ if (type != GL_NONE && mState.elementArrayBuffer.get())
{
- return error(GL_OUT_OF_MEMORY);
+ Buffer *indexBuffer = mState.elementArrayBuffer.get();
+ intptr_t offset = reinterpret_cast<intptr_t>(indices);
+ indices = static_cast<const GLubyte*>(indexBuffer->data()) + offset;
}
- ASSERT(SUCCEEDED(result));
+ UINT startIndex = 0;
+ bool succeeded = false;
- if (eventQuery)
+ if (supports32bitIndices())
{
- HRESULT result = eventQuery->Issue(D3DISSUE_END);
- ASSERT(SUCCEEDED(result));
+ const int spaceNeeded = (count + 1) * sizeof(unsigned int);
- result = eventQuery->GetData(NULL, 0, D3DGETDATA_FLUSH);
- eventQuery->Release();
-
- if (result == D3DERR_DEVICELOST)
+ if (!mLineLoopIB)
{
- error(GL_OUT_OF_MEMORY);
+ mLineLoopIB = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX32);
}
- }
-}
-
-void Context::drawClosingLine(unsigned int first, unsigned int last)
-{
- IDirect3DDevice9 *device = getDevice();
- IDirect3DIndexBuffer9 *indexBuffer = NULL;
- HRESULT result = D3DERR_INVALIDCALL;
-
- if (supports32bitIndices())
- {
- result = device->CreateIndexBuffer(8, D3DUSAGE_WRITEONLY, D3DFMT_INDEX32, D3DPOOL_DEFAULT, &indexBuffer, 0);
- if (SUCCEEDED(result))
+ if (mLineLoopIB)
{
- unsigned int *data;
- result = indexBuffer->Lock(0, 0, (void**)&data, 0);
+ mLineLoopIB->reserveSpace(spaceNeeded, GL_UNSIGNED_INT);
- if (SUCCEEDED(result))
+ UINT offset = 0;
+ unsigned int *data = static_cast<unsigned int*>(mLineLoopIB->map(spaceNeeded, &offset));
+ startIndex = offset / 4;
+
+ if (data)
{
- data[0] = last;
- data[1] = first;
+ switch (type)
+ {
+ case GL_NONE: // Non-indexed draw
+ for (int i = 0; i < count; i++)
+ {
+ data[i] = i;
+ }
+ data[count] = 0;
+ break;
+ case GL_UNSIGNED_BYTE:
+ for (int i = 0; i < count; i++)
+ {
+ data[i] = static_cast<const GLubyte*>(indices)[i];
+ }
+ data[count] = static_cast<const GLubyte*>(indices)[0];
+ break;
+ case GL_UNSIGNED_SHORT:
+ for (int i = 0; i < count; i++)
+ {
+ data[i] = static_cast<const GLushort*>(indices)[i];
+ }
+ data[count] = static_cast<const GLushort*>(indices)[0];
+ break;
+ case GL_UNSIGNED_INT:
+ for (int i = 0; i < count; i++)
+ {
+ data[i] = static_cast<const GLuint*>(indices)[i];
+ }
+ data[count] = static_cast<const GLuint*>(indices)[0];
+ break;
+ default: UNREACHABLE();
+ }
+
+ mLineLoopIB->unmap();
+ succeeded = true;
}
}
}
else
{
- result = device->CreateIndexBuffer(4, D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &indexBuffer, 0);
+ const int spaceNeeded = (count + 1) * sizeof(unsigned short);
- if (SUCCEEDED(result))
+ if (!mLineLoopIB)
{
- unsigned short *data;
- result = indexBuffer->Lock(0, 0, (void**)&data, 0);
+ mLineLoopIB = new StreamingIndexBuffer(mDevice, INITIAL_INDEX_BUFFER_SIZE, D3DFMT_INDEX16);
+ }
- if (SUCCEEDED(result))
+ if (mLineLoopIB)
+ {
+ mLineLoopIB->reserveSpace(spaceNeeded, GL_UNSIGNED_SHORT);
+
+ UINT offset = 0;
+ unsigned short *data = static_cast<unsigned short*>(mLineLoopIB->map(spaceNeeded, &offset));
+ startIndex = offset / 2;
+
+ if (data)
{
- data[0] = last;
- data[1] = first;
+ switch (type)
+ {
+ case GL_NONE: // Non-indexed draw
+ for (int i = 0; i < count; i++)
+ {
+ data[i] = i;
+ }
+ data[count] = 0;
+ break;
+ case GL_UNSIGNED_BYTE:
+ for (int i = 0; i < count; i++)
+ {
+ data[i] = static_cast<const GLubyte*>(indices)[i];
+ }
+ data[count] = static_cast<const GLubyte*>(indices)[0];
+ break;
+ case GL_UNSIGNED_SHORT:
+ for (int i = 0; i < count; i++)
+ {
+ data[i] = static_cast<const GLushort*>(indices)[i];
+ }
+ data[count] = static_cast<const GLushort*>(indices)[0];
+ break;
+ case GL_UNSIGNED_INT:
+ for (int i = 0; i < count; i++)
+ {
+ data[i] = static_cast<const GLuint*>(indices)[i];
+ }
+ data[count] = static_cast<const GLuint*>(indices)[0];
+ break;
+ default: UNREACHABLE();
+ }
+
+ mLineLoopIB->unmap();
+ succeeded = true;
}
}
}
- if (SUCCEEDED(result))
+ if (succeeded)
{
- indexBuffer->Unlock();
- device->SetIndices(indexBuffer);
-
- device->DrawIndexedPrimitive(D3DPT_LINELIST, 0, 0, 2, 0, 1);
+ if (mAppliedIBSerial != mLineLoopIB->getSerial())
+ {
+ mDevice->SetIndices(mLineLoopIB->getBuffer());
+ mAppliedIBSerial = mLineLoopIB->getSerial();
+ }
- indexBuffer->Release();
+ mDevice->DrawIndexedPrimitive(D3DPT_LINESTRIP, -minIndex, minIndex, count, startIndex, count);
}
else
{
- ERR("Could not create an index buffer for closing a line loop.");
- error(GL_OUT_OF_MEMORY);
- }
-}
-
-void Context::drawClosingLine(GLsizei count, GLenum type, const void *indices)
-{
- unsigned int first = 0;
- unsigned int last = 0;
-
- if (mState.elementArrayBuffer.get())
- {
- Buffer *indexBuffer = mState.elementArrayBuffer.get();
- intptr_t offset = reinterpret_cast<intptr_t>(indices);
- indices = static_cast<const GLubyte*>(indexBuffer->data()) + offset;
- }
-
- switch (type)
- {
- case GL_UNSIGNED_BYTE:
- first = static_cast<const GLubyte*>(indices)[0];
- last = static_cast<const GLubyte*>(indices)[count - 1];
- break;
- case GL_UNSIGNED_SHORT:
- first = static_cast<const GLushort*>(indices)[0];
- last = static_cast<const GLushort*>(indices)[count - 1];
- break;
- case GL_UNSIGNED_INT:
- first = static_cast<const GLuint*>(indices)[0];
- last = static_cast<const GLuint*>(indices)[count - 1];
- break;
- default: UNREACHABLE();
+ ERR("Could not create a looping index buffer for GL_LINE_LOOP.");
+ return error(GL_OUT_OF_MEMORY);
}
-
- drawClosingLine(first, last);
}
void Context::recordInvalidEnum()
@@ -2907,6 +3283,36 @@ GLenum Context::getError()
return GL_NO_ERROR;
}
+GLenum Context::getResetStatus()
+{
+ if (mResetStatus == GL_NO_ERROR)
+ {
+ bool lost = mDisplay->testDeviceLost();
+
+ if (lost)
+ {
+ mDisplay->notifyDeviceLost(); // Sets mResetStatus
+ }
+ }
+
+ GLenum status = mResetStatus;
+
+ if (mResetStatus != GL_NO_ERROR)
+ {
+ if (mDisplay->testDeviceResettable())
+ {
+ mResetStatus = GL_NO_ERROR;
+ }
+ }
+
+ return status;
+}
+
+bool Context::isResetNotificationEnabled()
+{
+ return (mResetStrategy == GL_LOSE_CONTEXT_ON_RESET_EXT);
+}
+
bool Context::supportsShaderModel3() const
{
return mSupportsShaderModel3;
@@ -2917,6 +3323,16 @@ int Context::getMaximumVaryingVectors() const
return mSupportsShaderModel3 ? MAX_VARYING_VECTORS_SM3 : MAX_VARYING_VECTORS_SM2;
}
+unsigned int Context::getMaximumVertexTextureImageUnits() const
+{
+ return mSupportsVertexTexture ? MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF : 0;
+}
+
+unsigned int Context::getMaximumCombinedTextureImageUnits() const
+{
+ return MAX_TEXTURE_IMAGE_UNITS + getMaximumVertexTextureImageUnits();
+}
+
int Context::getMaximumFragmentUniformVectors() const
{
return mSupportsShaderModel3 ? MAX_FRAGMENT_UNIFORM_VECTORS_SM3 : MAX_FRAGMENT_UNIFORM_VECTORS_SM2;
@@ -2956,39 +3372,54 @@ bool Context::supportsEventQueries() const
return mSupportsEventQueries;
}
-bool Context::supportsCompressedTextures() const
+bool Context::supportsOcclusionQueries() const
+{
+ return mSupportsOcclusionQueries;
+}
+
+bool Context::supportsDXT1Textures() const
+{
+ return mSupportsDXT1Textures;
+}
+
+bool Context::supportsDXT3Textures() const
+{
+ return mSupportsDXT3Textures;
+}
+
+bool Context::supportsDXT5Textures() const
{
- return mSupportsCompressedTextures;
+ return mSupportsDXT5Textures;
}
-bool Context::supportsFloatTextures() const
+bool Context::supportsFloat32Textures() const
{
- return mSupportsFloatTextures;
+ return mSupportsFloat32Textures;
}
-bool Context::supportsFloatLinearFilter() const
+bool Context::supportsFloat32LinearFilter() const
{
- return mSupportsFloatLinearFilter;
+ return mSupportsFloat32LinearFilter;
}
-bool Context::supportsFloatRenderableTextures() const
+bool Context::supportsFloat32RenderableTextures() const
{
- return mSupportsFloatRenderableTextures;
+ return mSupportsFloat32RenderableTextures;
}
-bool Context::supportsHalfFloatTextures() const
+bool Context::supportsFloat16Textures() const
{
- return mSupportsHalfFloatTextures;
+ return mSupportsFloat16Textures;
}
-bool Context::supportsHalfFloatLinearFilter() const
+bool Context::supportsFloat16LinearFilter() const
{
- return mSupportsHalfFloatLinearFilter;
+ return mSupportsFloat16LinearFilter;
}
-bool Context::supportsHalfFloatRenderableTextures() const
+bool Context::supportsFloat16RenderableTextures() const
{
- return mSupportsHalfFloatRenderableTextures;
+ return mSupportsFloat16RenderableTextures;
}
int Context::getMaximumRenderbufferDimension() const
@@ -3026,6 +3457,16 @@ bool Context::supports32bitIndices() const
return mSupports32bitIndices;
}
+bool Context::supportsNonPower2Texture() const
+{
+ return mSupportsNonPower2Texture;
+}
+
+bool Context::supportsInstancing() const
+{
+ return mSupportsInstancing;
+}
+
void Context::detachBuffer(GLuint buffer)
{
// [OpenGL ES 2.0.24] section 2.9 page 22:
@@ -3057,9 +3498,9 @@ void Context::detachTexture(GLuint texture)
// If a texture object is deleted, it is as if all texture units which are bound to that texture object are
// rebound to texture object zero
- for (int type = 0; type < SAMPLER_TYPE_COUNT; type++)
+ for (int type = 0; type < TEXTURE_TYPE_COUNT; type++)
{
- for (int sampler = 0; sampler < MAX_TEXTURE_IMAGE_UNITS; sampler++)
+ for (int sampler = 0; sampler < MAX_COMBINED_TEXTURE_IMAGE_UNITS_VTF; sampler++)
{
if (mState.samplerTexture[type][sampler].id() == texture)
{
@@ -3134,7 +3575,7 @@ void Context::detachRenderbuffer(GLuint renderbuffer)
}
}
-Texture *Context::getIncompleteTexture(SamplerType type)
+Texture *Context::getIncompleteTexture(TextureType type)
{
Texture *t = mIncompleteTextures[type].get();
@@ -3146,26 +3587,26 @@ Texture *Context::getIncompleteTexture(SamplerType type)
{
default:
UNREACHABLE();
- // default falls through to SAMPLER_2D
+ // default falls through to TEXTURE_2D
- case SAMPLER_2D:
+ case TEXTURE_2D:
{
Texture2D *incomplete2d = new Texture2D(Texture::INCOMPLETE_TEXTURE_ID);
- incomplete2d->setImage(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
+ incomplete2d->setImage(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
t = incomplete2d;
}
break;
- case SAMPLER_CUBE:
+ case TEXTURE_CUBE:
{
TextureCubeMap *incompleteCube = new TextureCubeMap(Texture::INCOMPLETE_TEXTURE_ID);
- incompleteCube->setImagePosX(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
- incompleteCube->setImageNegX(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
- incompleteCube->setImagePosY(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
- incompleteCube->setImageNegY(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
- incompleteCube->setImagePosZ(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
- incompleteCube->setImageNegZ(0, GL_RGBA, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
+ incompleteCube->setImagePosX(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
+ incompleteCube->setImageNegX(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
+ incompleteCube->setImagePosY(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
+ incompleteCube->setImageNegY(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
+ incompleteCube->setImagePosZ(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
+ incompleteCube->setImageNegZ(0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, color);
t = incompleteCube;
}
@@ -3214,53 +3655,100 @@ void Context::setVertexAttrib(GLuint index, const GLfloat *values)
mVertexDataManager->dirtyCurrentValue(index);
}
+void Context::setVertexAttribDivisor(GLuint index, GLuint divisor)
+{
+ ASSERT(index < gl::MAX_VERTEX_ATTRIBS);
+
+ mState.vertexAttribute[index].mDivisor = divisor;
+}
+
+// keep list sorted in following order
+// OES extensions
+// EXT extensions
+// Vendor extensions
void Context::initExtensionString()
{
+ mExtensionString = "";
+
+ // OES extensions
+ if (supports32bitIndices())
+ {
+ mExtensionString += "GL_OES_element_index_uint ";
+ }
+
mExtensionString += "GL_OES_packed_depth_stencil ";
- mExtensionString += "GL_EXT_texture_format_BGRA8888 ";
- mExtensionString += "GL_EXT_read_format_bgra ";
- mExtensionString += "GL_ANGLE_framebuffer_blit ";
mExtensionString += "GL_OES_rgb8_rgba8 ";
mExtensionString += "GL_OES_standard_derivatives ";
- if (supportsEventQueries())
+ if (supportsFloat16Textures())
{
- mExtensionString += "GL_NV_fence ";
+ mExtensionString += "GL_OES_texture_half_float ";
}
-
- if (supportsCompressedTextures())
+ if (supportsFloat16LinearFilter())
{
- mExtensionString += "GL_EXT_texture_compression_dxt1 ";
+ mExtensionString += "GL_OES_texture_half_float_linear ";
}
-
- if (supportsFloatTextures())
+ if (supportsFloat32Textures())
{
mExtensionString += "GL_OES_texture_float ";
}
+ if (supportsFloat32LinearFilter())
+ {
+ mExtensionString += "GL_OES_texture_float_linear ";
+ }
- if (supportsHalfFloatTextures())
+ if (supportsNonPower2Texture())
{
- mExtensionString += "GL_OES_texture_half_float ";
+ mExtensionString += "GL_OES_texture_npot ";
}
- if (supportsFloatLinearFilter())
+ // Multi-vendor (EXT) extensions
+ if (supportsOcclusionQueries())
{
- mExtensionString += "GL_OES_texture_float_linear ";
+ mExtensionString += "GL_EXT_occlusion_query_boolean ";
}
- if (supportsHalfFloatLinearFilter())
+ mExtensionString += "GL_EXT_read_format_bgra ";
+ mExtensionString += "GL_EXT_robustness ";
+
+ if (supportsDXT1Textures())
{
- mExtensionString += "GL_OES_texture_half_float_linear ";
+ mExtensionString += "GL_EXT_texture_compression_dxt1 ";
}
+ mExtensionString += "GL_EXT_texture_format_BGRA8888 ";
+ mExtensionString += "GL_EXT_texture_storage ";
+
+ // ANGLE-specific extensions
+ mExtensionString += "GL_ANGLE_framebuffer_blit ";
if (getMaxSupportedSamples() != 0)
{
mExtensionString += "GL_ANGLE_framebuffer_multisample ";
}
- if (supports32bitIndices())
+ if (supportsInstancing())
{
- mExtensionString += "GL_OES_element_index_uint ";
+ mExtensionString += "GL_ANGLE_instanced_arrays ";
+ }
+
+ mExtensionString += "GL_ANGLE_pack_reverse_row_order ";
+
+ if (supportsDXT3Textures())
+ {
+ mExtensionString += "GL_ANGLE_texture_compression_dxt3 ";
+ }
+ if (supportsDXT5Textures())
+ {
+ mExtensionString += "GL_ANGLE_texture_compression_dxt5 ";
+ }
+
+ mExtensionString += "GL_ANGLE_texture_usage ";
+ mExtensionString += "GL_ANGLE_translated_shader_source ";
+
+ // Other vendor-specific extensions
+ if (supportsEventQueries())
+ {
+ mExtensionString += "GL_NV_fence ";
}
std::string::size_type end = mExtensionString.find_last_not_of(' ');
@@ -3275,12 +3763,24 @@ const char *Context::getExtensionString() const
return mExtensionString.c_str();
}
+void Context::initRendererString()
+{
+ D3DADAPTER_IDENTIFIER9 *identifier = mDisplay->getAdapterIdentifier();
+
+ mRendererString = "ANGLE (";
+ mRendererString += identifier->Description;
+ mRendererString += ")";
+}
+
+const char *Context::getRendererString() const
+{
+ return mRendererString.c_str();
+}
+
void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask)
{
- IDirect3DDevice9 *device = getDevice();
-
Framebuffer *readFramebuffer = getReadFramebuffer();
Framebuffer *drawFramebuffer = getDrawFramebuffer();
@@ -3295,6 +3795,11 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1
return error(GL_INVALID_OPERATION);
}
+ int readBufferWidth = readFramebuffer->getColorbuffer()->getWidth();
+ int readBufferHeight = readFramebuffer->getColorbuffer()->getHeight();
+ int drawBufferWidth = drawFramebuffer->getColorbuffer()->getWidth();
+ int drawBufferHeight = drawFramebuffer->getColorbuffer()->getHeight();
+
RECT sourceRect;
RECT destRect;
@@ -3313,21 +3818,19 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1
destRect.right = dstX0;
}
- // Arguments to StretchRect must be in D3D-style (0-top) coordinates, so we must
- // flip our Y-values here
if (srcY0 < srcY1)
{
- sourceRect.bottom = srcY1;
- destRect.bottom = dstY1;
- sourceRect.top = srcY0;
- destRect.top = dstY0;
+ sourceRect.top = readBufferHeight - srcY1;
+ destRect.top = drawBufferHeight - dstY1;
+ sourceRect.bottom = readBufferHeight - srcY0;
+ destRect.bottom = drawBufferHeight - dstY0;
}
else
{
- sourceRect.bottom = srcY0;
- destRect.bottom = dstY0;
- sourceRect.top = srcY1;
- destRect.top = dstY1;
+ sourceRect.top = readBufferHeight - srcY0;
+ destRect.top = drawBufferHeight - dstY0;
+ sourceRect.bottom = readBufferHeight - srcY1;
+ destRect.bottom = drawBufferHeight - dstY1;
}
RECT sourceScissoredRect = sourceRect;
@@ -3382,11 +3885,6 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1
destTrimmedRect.left += xDiff;
}
- int readBufferWidth = readFramebuffer->getColorbuffer()->getWidth();
- int readBufferHeight = readFramebuffer->getColorbuffer()->getHeight();
- int drawBufferWidth = drawFramebuffer->getColorbuffer()->getWidth();
- int drawBufferHeight = drawFramebuffer->getColorbuffer()->getHeight();
-
if (sourceTrimmedRect.right > readBufferWidth)
{
int xDiff = sourceTrimmedRect.right - readBufferWidth;
@@ -3470,8 +3968,8 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1
if (mask & (GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
{
- DepthStencilbuffer *readDSBuffer = NULL;
- DepthStencilbuffer *drawDSBuffer = NULL;
+ Renderbuffer *readDSBuffer = NULL;
+ Renderbuffer *drawDSBuffer = NULL;
// We support OES_packed_depth_stencil, and do not support a separately attached depth and stencil buffer, so if we have
// both a depth and stencil buffer, it will be the same buffer.
@@ -3523,13 +4021,18 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1
if (blitRenderTarget || blitDepthStencil)
{
- egl::Display *display = getDisplay();
- display->endScene();
+ mDisplay->endScene();
if (blitRenderTarget)
{
- HRESULT result = device->StretchRect(readFramebuffer->getRenderTarget(), &sourceTrimmedRect,
- drawFramebuffer->getRenderTarget(), &destTrimmedRect, D3DTEXF_NONE);
+ IDirect3DSurface9* readRenderTarget = readFramebuffer->getRenderTarget();
+ IDirect3DSurface9* drawRenderTarget = drawFramebuffer->getRenderTarget();
+
+ HRESULT result = mDevice->StretchRect(readRenderTarget, &sourceTrimmedRect,
+ drawRenderTarget, &destTrimmedRect, D3DTEXF_NONE);
+
+ readRenderTarget->Release();
+ drawRenderTarget->Release();
if (FAILED(result))
{
@@ -3540,7 +4043,7 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1
if (blitDepthStencil)
{
- HRESULT result = device->StretchRect(readFramebuffer->getDepthStencil(), NULL, drawFramebuffer->getDepthStencil(), NULL, D3DTEXF_NONE);
+ HRESULT result = mDevice->StretchRect(readFramebuffer->getDepthStencil(), NULL, drawFramebuffer->getDepthStencil(), NULL, D3DTEXF_NONE);
if (FAILED(result))
{
@@ -3551,13 +4054,204 @@ void Context::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1
}
}
+VertexDeclarationCache::VertexDeclarationCache() : mMaxLru(0)
+{
+ for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
+ {
+ mVertexDeclCache[i].vertexDeclaration = NULL;
+ mVertexDeclCache[i].lruCount = 0;
+ }
+}
+
+VertexDeclarationCache::~VertexDeclarationCache()
+{
+ for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
+ {
+ if (mVertexDeclCache[i].vertexDeclaration)
+ {
+ mVertexDeclCache[i].vertexDeclaration->Release();
+ }
+ }
+}
+
+GLenum VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], Program *program, GLsizei instances, GLsizei *repeatDraw)
+{
+ *repeatDraw = 1;
+
+ int indexedAttribute = MAX_VERTEX_ATTRIBS;
+ int instancedAttribute = MAX_VERTEX_ATTRIBS;
+
+ if (instances > 0)
+ {
+ // Find an indexed attribute to be mapped to D3D stream 0
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ if (attributes[i].active)
+ {
+ if (indexedAttribute == MAX_VERTEX_ATTRIBS)
+ {
+ if (attributes[i].divisor == 0)
+ {
+ indexedAttribute = i;
+ }
+ }
+ else if (instancedAttribute == MAX_VERTEX_ATTRIBS)
+ {
+ if (attributes[i].divisor != 0)
+ {
+ instancedAttribute = i;
+ }
+ }
+ else break; // Found both an indexed and instanced attribute
+ }
+ }
+
+ if (indexedAttribute == MAX_VERTEX_ATTRIBS)
+ {
+ return GL_INVALID_OPERATION;
+ }
+ }
+
+ D3DVERTEXELEMENT9 elements[MAX_VERTEX_ATTRIBS + 1];
+ D3DVERTEXELEMENT9 *element = &elements[0];
+
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ if (attributes[i].active)
+ {
+ int stream = i;
+
+ if (instances > 0)
+ {
+ // Due to a bug on ATI cards we can't enable instancing when none of the attributes are instanced.
+ if (instancedAttribute == MAX_VERTEX_ATTRIBS)
+ {
+ *repeatDraw = instances;
+ }
+ else
+ {
+ if (i == indexedAttribute)
+ {
+ stream = 0;
+ }
+ else if (i == 0)
+ {
+ stream = indexedAttribute;
+ }
+
+ UINT frequency = 1;
+
+ if (attributes[i].divisor == 0)
+ {
+ frequency = D3DSTREAMSOURCE_INDEXEDDATA | instances;
+ }
+ else
+ {
+ frequency = D3DSTREAMSOURCE_INSTANCEDATA | attributes[i].divisor;
+ }
+
+ device->SetStreamSourceFreq(stream, frequency);
+ mInstancingEnabled = true;
+ }
+ }
+
+ if (mAppliedVBs[stream].serial != attributes[i].serial ||
+ mAppliedVBs[stream].stride != attributes[i].stride ||
+ mAppliedVBs[stream].offset != attributes[i].offset)
+ {
+ device->SetStreamSource(stream, attributes[i].vertexBuffer, attributes[i].offset, attributes[i].stride);
+ mAppliedVBs[stream].serial = attributes[i].serial;
+ mAppliedVBs[stream].stride = attributes[i].stride;
+ mAppliedVBs[stream].offset = attributes[i].offset;
+ }
+
+ element->Stream = stream;
+ element->Offset = 0;
+ element->Type = attributes[i].type;
+ element->Method = D3DDECLMETHOD_DEFAULT;
+ element->Usage = D3DDECLUSAGE_TEXCOORD;
+ element->UsageIndex = program->getSemanticIndex(i);
+ element++;
+ }
+ }
+
+ if (instances == 0 || instancedAttribute == MAX_VERTEX_ATTRIBS)
+ {
+ if (mInstancingEnabled)
+ {
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ device->SetStreamSourceFreq(i, 1);
+ }
+
+ mInstancingEnabled = false;
+ }
+ }
+
+ static const D3DVERTEXELEMENT9 end = D3DDECL_END();
+ *(element++) = end;
+
+ for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
+ {
+ VertexDeclCacheEntry *entry = &mVertexDeclCache[i];
+ if (memcmp(entry->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9)) == 0 && entry->vertexDeclaration)
+ {
+ entry->lruCount = ++mMaxLru;
+ if(entry->vertexDeclaration != mLastSetVDecl)
+ {
+ device->SetVertexDeclaration(entry->vertexDeclaration);
+ mLastSetVDecl = entry->vertexDeclaration;
+ }
+
+ return GL_NO_ERROR;
+ }
+ }
+
+ VertexDeclCacheEntry *lastCache = mVertexDeclCache;
+
+ for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++)
+ {
+ if (mVertexDeclCache[i].lruCount < lastCache->lruCount)
+ {
+ lastCache = &mVertexDeclCache[i];
+ }
+ }
+
+ if (lastCache->vertexDeclaration != NULL)
+ {
+ lastCache->vertexDeclaration->Release();
+ lastCache->vertexDeclaration = NULL;
+ // mLastSetVDecl is set to the replacement, so we don't have to worry
+ // about it.
+ }
+
+ memcpy(lastCache->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9));
+ device->CreateVertexDeclaration(elements, &lastCache->vertexDeclaration);
+ device->SetVertexDeclaration(lastCache->vertexDeclaration);
+ mLastSetVDecl = lastCache->vertexDeclaration;
+ lastCache->lruCount = ++mMaxLru;
+
+ return GL_NO_ERROR;
+}
+
+void VertexDeclarationCache::markStateDirty()
+{
+ for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+ {
+ mAppliedVBs[i].serial = 0;
+ }
+
+ mLastSetVDecl = NULL;
+ mInstancingEnabled = true; // Forces it to be disabled when not used
+}
+
}
extern "C"
{
-gl::Context *glCreateContext(const egl::Config *config, const gl::Context *shareContext)
+gl::Context *glCreateContext(const egl::Config *config, const gl::Context *shareContext, bool notifyResets, bool robustAccess)
{
- return new gl::Context(config, shareContext);
+ return new gl::Context(config, shareContext, notifyResets, robustAccess);
}
void glDestroyContext(gl::Context *context)