Add an abstract Renderer::setViewport method and implemented it for Renderer9.

TRAC #22116

Signed-off-by: Shannon Woods
Signed-off-by: Daniel Koch

git-svn-id: https://angleproject.googlecode.com/svn/branches/dx11proto@1453 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/libGLESv2/renderer/Renderer.h b/src/libGLESv2/renderer/Renderer.h
index 0fc21b2..4c7b8b7 100644
--- a/src/libGLESv2/renderer/Renderer.h
+++ b/src/libGLESv2/renderer/Renderer.h
@@ -37,6 +37,11 @@
 class Display;
 }
 
+namespace gl
+{
+class ProgramBinary;
+}
+
 namespace rx
 {
 class TextureStorage2D;
@@ -81,6 +86,9 @@
 
     virtual void setScissorRectangle(const gl::Rectangle& scissor, unsigned int renderTargetWidth,
                                      unsigned int renderTargetHeight) = 0;
+    virtual bool setViewport(const gl::Rectangle& viewport, float zNear, float zFar,
+                             unsigned int renderTargetWidth, unsigned int renderTargetHeight,
+                             gl::ProgramBinary *currentProgram, bool forceSetUniforms) = 0;
 
     virtual void applyRenderTarget(gl::Framebuffer *frameBuffer) = 0;
 
diff --git a/src/libGLESv2/renderer/Renderer11.cpp b/src/libGLESv2/renderer/Renderer11.cpp
index 8c3e679..bbdb731 100644
--- a/src/libGLESv2/renderer/Renderer11.cpp
+++ b/src/libGLESv2/renderer/Renderer11.cpp
@@ -374,6 +374,15 @@
     mForceSetScissor = false;
 }
 
+bool Renderer11::setViewport(const gl::Rectangle& viewport, float zNear, float zFar,
+                             unsigned int renderTargetWidth, unsigned int renderTargetHeight,
+                             gl::ProgramBinary *currentProgram, bool forceSetUniforms)
+{
+    // TODO
+    UNIMPLEMENTED();
+    return true;
+}
+
 void Renderer11::applyRenderTarget(gl::Framebuffer *frameBuffer)
 {
     // TODO
diff --git a/src/libGLESv2/renderer/Renderer11.h b/src/libGLESv2/renderer/Renderer11.h
index ed6aa0e..12c6344 100644
--- a/src/libGLESv2/renderer/Renderer11.h
+++ b/src/libGLESv2/renderer/Renderer11.h
@@ -57,6 +57,9 @@
 
     virtual void setScissorRectangle(const gl::Rectangle& scissor, unsigned int renderTargetWidth,
                                      unsigned int renderTargetHeight);
+    virtual bool setViewport(const gl::Rectangle& viewport, float zNear, float zFar,
+                             unsigned int renderTargetWidth, unsigned int renderTargetHeight,
+                             gl::ProgramBinary *currentProgram, bool forceSetUniforms);
 
     virtual void applyRenderTarget(gl::Framebuffer *frameBuffer);
 
diff --git a/src/libGLESv2/renderer/Renderer9.cpp b/src/libGLESv2/renderer/Renderer9.cpp
index c496af0..908c3e8 100644
--- a/src/libGLESv2/renderer/Renderer9.cpp
+++ b/src/libGLESv2/renderer/Renderer9.cpp
@@ -11,6 +11,8 @@
 #include "libGLESv2/utilities.h"
 #include "libGLESv2/mathutil.h"
 #include "libGLESv2/Framebuffer.h"
+#include "libGLESv2/Program.h"
+#include "libGLESv2/ProgramBinary.h"
 #include "libGLESv2/renderer/Renderer9.h"
 #include "libGLESv2/renderer/renderer9_utils.h"
 #include "libGLESv2/renderer/SwapChain9.h"
@@ -86,6 +88,7 @@
     mForceSetRasterState = true;
     mForceSetBlendState = true;
     mForceSetScissor = true;
+    mForceSetViewport = true;
 }
 
 Renderer9::~Renderer9()
@@ -869,9 +872,67 @@
     mForceSetScissor = false;
 }
 
+bool Renderer9::setViewport(const gl::Rectangle& viewport, float zNear, float zFar,
+                            unsigned int renderTargetWidth, unsigned int renderTargetHeight,
+                            gl::ProgramBinary *currentProgram, bool forceSetUniforms)
+{
+    bool viewportChanged =  mForceSetViewport || memcmp(&viewport, &mCurViewport, sizeof(gl::Rectangle)) != 0 ||
+                            zNear != mCurNear || zFar != mCurFar;
+
+    D3DVIEWPORT9 dxViewport;
+    dxViewport.X = gl::clamp(viewport.x, 0, static_cast<int>(renderTargetWidth));
+    dxViewport.Y = gl::clamp(viewport.y, 0, static_cast<int>(renderTargetHeight));
+    dxViewport.Width = gl::clamp(viewport.width, 0, static_cast<int>(renderTargetWidth) - static_cast<int>(dxViewport.X));
+    dxViewport.Height = gl::clamp(viewport.height, 0, static_cast<int>(renderTargetHeight) - static_cast<int>(dxViewport.Y));
+    dxViewport.MinZ = zNear;
+    dxViewport.MaxZ = zFar;
+
+    if (dxViewport.Width <= 0 || dxViewport.Height <= 0)
+    {
+        return false;   // Nothing to render
+    }
+
+    if (viewportChanged)
+    {
+        mDevice->SetViewport(&dxViewport);
+
+        mCurViewport = viewport;
+        mCurNear = zNear;
+        mCurFar = zFar;
+    }
+
+    if (currentProgram && (viewportChanged || forceSetUniforms))
+    {
+        GLint halfPixelSize = currentProgram->getDxHalfPixelSizeLocation();
+        GLfloat xy[2] = { 1.0f / dxViewport.Width, -1.0f / dxViewport.Height };
+        currentProgram->setUniform2fv(halfPixelSize, 1, xy);
+
+        // These values are used for computing gl_FragCoord in Program::linkVaryings().
+        GLint coord = currentProgram->getDxCoordLocation();
+        GLfloat whxy[4] = { viewport.width  * 0.5f,
+                            viewport.height * 0.5f,
+                            viewport.x + (viewport.width  * 0.5f),
+                            viewport.y + (viewport.height * 0.5f) };
+        currentProgram->setUniform4fv(coord, 1, whxy);
+
+        GLint depth = currentProgram->getDxDepthLocation();
+        GLfloat dz[2] = { (zFar - zNear) * 0.5f, (zNear + zFar) * 0.5f };
+        currentProgram->setUniform2fv(depth, 1, dz);
+
+        GLint depthRange = currentProgram->getDxDepthRangeLocation();
+        GLfloat nearFarDiff[3] = { zNear, zFar, zFar - zNear };
+        currentProgram->setUniform3fv(depthRange, 1, nearFarDiff);
+    }
+
+    mForceSetViewport = false;
+    return true;
+}
+
 void Renderer9::applyRenderTarget(gl::Framebuffer *frameBuffer)
 {
+    // TODO: only set these when the rendertarget actually changes
     mForceSetScissor = true;
+    mForceSetViewport = true;
 
     // TODO
 }
diff --git a/src/libGLESv2/renderer/Renderer9.h b/src/libGLESv2/renderer/Renderer9.h
index 1770727..520c4a9 100644
--- a/src/libGLESv2/renderer/Renderer9.h
+++ b/src/libGLESv2/renderer/Renderer9.h
@@ -65,8 +65,6 @@
     // state setup
     void applyShaders();
     void applyConstants();
-    void applyRenderTargets();
-    void applyState();
 #endif
     virtual void setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &sampler);
     virtual void setTexture(gl::SamplerType type, int index, gl::Texture *texture);
@@ -79,6 +77,9 @@
 
     virtual void setScissorRectangle(const gl::Rectangle& scissor, unsigned int renderTargetWidth,
                                      unsigned int renderTargetHeight);
+    virtual bool setViewport(const gl::Rectangle& viewport, float zNear, float zFar,
+                             unsigned int renderTargetWidth, unsigned int renderTargetHeight,
+                             gl::ProgramBinary *currentProgram, bool forceSetUniforms);
 
     virtual void applyRenderTarget(gl::Framebuffer *frameBuffer);
 
@@ -205,6 +206,11 @@
     unsigned int mCurRenderTargetWidth;
     unsigned int mCurRenderTargetHeight;
 
+    bool mForceSetViewport;
+    gl::Rectangle mCurViewport;
+    float mCurNear;
+    float mCurFar;
+
     bool mForceSetBlendState;
     gl::BlendState mCurBlendState;
     gl::Color mCurBlendColor;