Implement larger bounds for viewports and scissor rectangles in D3D11.

This fixes a bug where we would not allow the application to draw outside the viewport, which is valid.

TRAC #22497

Signed-off-by: Nicolas Capens
Signed-off-by: Shannon Woods
Author: Jamie Madill

git-svn-id: https://angleproject.googlecode.com/svn/branches/dx11proto@1875 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/renderer/Renderer11.cpp b/src/libGLESv2/renderer/Renderer11.cpp
index 099d931..56fa133 100644
--- a/src/libGLESv2/renderer/Renderer11.cpp
+++ b/src/libGLESv2/renderer/Renderer11.cpp
@@ -562,10 +562,10 @@
         if (enabled)
         {
             D3D11_RECT rect;
-            rect.left = gl::clamp(scissor.x, 0, static_cast<int>(mRenderTargetDesc.width));
-            rect.top = gl::clamp(scissor.y, 0, static_cast<int>(mRenderTargetDesc.height));
-            rect.right = gl::clamp(scissor.x + scissor.width, 0, static_cast<int>(mRenderTargetDesc.width));
-            rect.bottom = gl::clamp(scissor.y + scissor.height, 0, static_cast<int>(mRenderTargetDesc.height));
+            rect.left = std::max(0, scissor.x);
+            rect.top = std::max(0, scissor.y);
+            rect.right = scissor.x + std::max(0, scissor.width);
+            rect.bottom = scissor.y + std::max(0, scissor.height);
 
             mDeviceContext->RSSetScissorRects(1, &rect);
         }
@@ -598,11 +598,17 @@
         actualZFar = 1.0f;
     }
 
+    // Get D3D viewport bounds, which depends on the feature level
+    const Range& viewportBounds = getViewportBounds();
+
+    // Clamp width and height first to the gl maximum, then clamp further if we extend past the D3D maximum bounds
     D3D11_VIEWPORT dxViewport;
-    dxViewport.TopLeftX = gl::clamp(actualViewport.x, 0, static_cast<int>(mRenderTargetDesc.width));
-    dxViewport.TopLeftY = gl::clamp(actualViewport.y, 0, static_cast<int>(mRenderTargetDesc.height));
-    dxViewport.Width = gl::clamp(actualViewport.width, 0, static_cast<int>(mRenderTargetDesc.width) - static_cast<int>(dxViewport.TopLeftX));
-    dxViewport.Height = gl::clamp(actualViewport.height, 0, static_cast<int>(mRenderTargetDesc.height) - static_cast<int>(dxViewport.TopLeftY));
+    dxViewport.TopLeftX = gl::clamp(actualViewport.x, viewportBounds.start, viewportBounds.end);
+    dxViewport.TopLeftY = gl::clamp(actualViewport.y, viewportBounds.start, viewportBounds.end);
+    dxViewport.Width = gl::clamp(actualViewport.width, 0, getMaxViewportDimension());
+    dxViewport.Height = gl::clamp(actualViewport.height, 0, getMaxViewportDimension());
+    dxViewport.Width = std::min((int)dxViewport.Width, viewportBounds.end - static_cast<int>(dxViewport.TopLeftX));
+    dxViewport.Height = std::min((int)dxViewport.Height, viewportBounds.end - static_cast<int>(dxViewport.TopLeftY));
     dxViewport.MinDepth = actualZNear;
     dxViewport.MaxDepth = actualZFar;
 
@@ -793,8 +799,8 @@
         mRenderTargetDesc.width = renderTargetWidth;
         mRenderTargetDesc.height = renderTargetHeight;
         mRenderTargetDesc.format = renderTargetFormat;
-        mForceSetViewport = true; // TODO: It may not be required to clamp the viewport in D3D11
-        mForceSetScissor = true; // TODO: It may not be required to clamp the scissor in D3D11
+        mForceSetViewport = true;
+        mForceSetScissor = true;
 
         if (!mDepthStencilInitialized || depthSize != mCurDepthSize)
         {
@@ -2023,6 +2029,20 @@
     return true;
 }
 
+Range Renderer11::getViewportBounds() const
+{
+    switch (mFeatureLevel)
+    {
+      case D3D_FEATURE_LEVEL_11_0:
+        return Range(D3D11_VIEWPORT_BOUNDS_MIN, D3D11_VIEWPORT_BOUNDS_MAX);
+      case D3D_FEATURE_LEVEL_10_1:
+      case D3D_FEATURE_LEVEL_10_0:
+        return Range(D3D10_VIEWPORT_BOUNDS_MIN, D3D10_VIEWPORT_BOUNDS_MAX);
+      default: UNREACHABLE();
+        return Range(0, 0);
+    }
+}
+
 unsigned int Renderer11::getMaxVertexTextureImageUnits() const
 {
     META_ASSERT(MAX_TEXTURE_IMAGE_UNITS_VTF_SM4 <= gl::IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS);
@@ -2160,6 +2180,21 @@
     return 1024.0f;
 }
 
+int Renderer11::getMaxViewportDimension() const
+{
+    // Clamp viewport width/height to half of the maximum right/bottom edge
+    switch (mFeatureLevel)
+    {
+      case D3D_FEATURE_LEVEL_11_0: 
+        return D3D11_VIEWPORT_BOUNDS_MAX - D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;   // 16384
+      case D3D_FEATURE_LEVEL_10_1:
+      case D3D_FEATURE_LEVEL_10_0: 
+        return D3D10_VIEWPORT_BOUNDS_MAX - D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;   // 8192
+      default: UNREACHABLE();      
+        return 0;
+    }
+}
+
 int Renderer11::getMaxTextureWidth() const
 {
     switch (mFeatureLevel)