void HSWDisplay::RenderInternal(ovrEyeType eye, const ovrTexture* eyeTexture)
{
    if(RenderEnabled && eyeTexture)
    {        
        // We need to render to the eyeTexture with the texture viewport.
        // Setup rendering to the texture.
        ovrGLTexture* eyeTextureGL = const_cast<ovrGLTexture*>(reinterpret_cast<const ovrGLTexture*>(eyeTexture));
        OVR_ASSERT(eyeTextureGL->Texture.Header.API == ovrRenderAPI_OpenGL);

        // We init a temporary Context, Bind our own context, then Bind the temporary context below before exiting.
        // It's more exensive to have a temp context copy made here instead of having it as a saved member variable,
        // but we can't have a saved member variable because the app might delete the saved member behind our back
        // or associate it with another thread, which would cause our bind of it before exiting to be a bad operation.
        Context currentGLContext; // To do: Change this to use the AutoContext class that was recently created.
        currentGLContext.InitFromCurrent();
        if(GLContext.GetIncarnation() == 0) // If not yet initialized...
            GLContext.CreateShared(currentGLContext);
        GLContext.Bind();
        #if defined(OVR_OS_MAC) // To consider: merge the following into the Bind function.
            GLContext.SetSurface(currentGLContext);
        #endif

        // Load the graphics if not loaded already.
        if (!pTexture)
            LoadGraphics();

        // Calculate ortho projection.
        GetOrthoProjection(RenderState, OrthoProjection);

        // Set the rendering to be to the eye texture.
        glBindFramebuffer(GL_FRAMEBUFFER, FrameBuffer);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, eyeTextureGL->OGL.TexId, 0);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); // We aren't using depth, as we currently want this to overwrite everything.
        GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
        OVR_ASSERT(status == GL_FRAMEBUFFER_COMPLETE); OVR_UNUSED(status);

        // Set up the viewport
        const GLint   x = (GLint)eyeTextureGL->Texture.Header.RenderViewport.Pos.x;
        const GLint   y = (GLint)eyeTextureGL->Texture.Header.RenderViewport.Pos.y; // Note that GL uses bottom-up coordinates.
        const GLsizei w = (GLsizei)eyeTextureGL->Texture.Header.RenderViewport.Size.w;
        const GLsizei h = (GLsizei)eyeTextureGL->Texture.Header.RenderViewport.Size.h;
        glViewport(x, y, w, h);

        // Set fixed-function render states.
        //glDepthRange(0.0,  1.0); // This is the default
        glDepthMask(GL_FALSE);
        glDisable(GL_DEPTH_TEST);
        glFrontFace(GL_CW);
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

        // Enable the buffer and shaders we use.
        ShaderFill fill(pShaderSet);
        if (pTexture)
            fill.SetTexture(0, pTexture);

        // Set shader uniforms.
        const float scale  = HSWDISPLAY_SCALE * ((RenderState.OurHMDInfo.HmdType == HmdType_DK1) ? 0.70f : 1.f);
        pShaderSet->SetUniform2f("Scale", scale, scale / 2.f); // X and Y scale. Y is a fixed proportion to X in order to give a certain aspect ratio.
        pShaderSet->SetUniform2f("PositionOffset", OrthoProjection[eye].GetTranslation().x, 0.0f);

        // Set vertex attributes
        if (GLVersionInfo.SupportsVAO)
        {
            OVR_ASSERT(VAO != 0);
            glBindVertexArray(VAO);
        }

        if(!VAOInitialized) // This executes for the case that VAO isn't supported.
        {
            glBindBuffer(GL_ARRAY_BUFFER, pVB->GLBuffer); // This must be called before glVertexAttribPointer is called below.

            const GLuint shaderProgram = pShaderSet->Prog;
            GLint attributeLocationArray[3];

            attributeLocationArray[0] = glGetAttribLocation(shaderProgram, "Position");
            glVertexAttribPointer(attributeLocationArray[0], sizeof(Vector3f)/sizeof(float), GL_FLOAT,         false, sizeof(HASWVertex), reinterpret_cast<char*>(offsetof(HASWVertex, Pos)));

            attributeLocationArray[1] = glGetAttribLocation(shaderProgram, "Color");
            glVertexAttribPointer(attributeLocationArray[1], sizeof(Color)/sizeof(uint8_t),  GL_UNSIGNED_BYTE,  true, sizeof(HASWVertex), reinterpret_cast<char*>(offsetof(HASWVertex, C)));  // True because we want it to convert [0,255] to [0,1] for us.

            attributeLocationArray[2] = glGetAttribLocation(shaderProgram, "TexCoord");
            glVertexAttribPointer(attributeLocationArray[2], sizeof(float[2])/sizeof(float), GL_FLOAT,         false, sizeof(HASWVertex), reinterpret_cast<char*>(offsetof(HASWVertex, U)));

            for (size_t i = 0; i < OVR_ARRAY_COUNT(attributeLocationArray); i++)
                glEnableVertexAttribArray((GLuint)i);
        }

        fill.Set(Prim_TriangleStrip);

        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

        if (GLVersionInfo.SupportsVAO)
        {
            VAOInitialized = true;
            glBindVertexArray(0);
        }
        
        currentGLContext.Bind();
    }
}
void HSWDisplay::RenderInternal(ovrEyeType eye, const ovrTexture* eyeTexture)
{
    if(RenderEnabled && eyeTexture)
    {
        // Note: The D3D9 implementation below is entirely fixed-function and isn't yet using shaders.
        // For the time being this is sufficient, but future designs will likely necessitate moving
        // to a system that uses programmable shaders.

        // We need to render to the eyeTexture with the texture viewport.
        // Setup rendering to the texture.
        ovrD3D9Texture* eyeTextureD3D9 = const_cast<ovrD3D9Texture*>(reinterpret_cast<const ovrD3D9Texture*>(eyeTexture));
        OVR_ASSERT(eyeTextureD3D9->Texture.Header.API == ovrRenderAPI_D3D9);


        // Save previous state.
        // To do: Merge this saved state with that done by DistortionRenderer::GraphicsState::Save(), and put them in a shared location.
        DWORD fvfSaved;
        RenderParams.Device->GetFVF(&fvfSaved);

        Ptr<IDirect3DVertexBuffer9> pVBDSaved;
        UINT vbOffsetSaved;
        UINT vbStrideSaved;
        RenderParams.Device->GetStreamSource(0, &pVBDSaved.GetRawRef(), &vbOffsetSaved, &vbStrideSaved);

        Ptr<IDirect3DBaseTexture9> pTexture0Saved;
        RenderParams.Device->GetTexture(0, &pTexture0Saved.GetRawRef());
        Ptr<IDirect3DBaseTexture9> pTexture1Saved;
        RenderParams.Device->GetTexture(1, &pTexture1Saved.GetRawRef());

        D3DMATRIX worldMatrixSaved, viewMatrixSaved, projectionMatrixSaved, texture0MatrixSaved;
        RenderParams.Device->GetTransform(D3DTS_WORLD, &worldMatrixSaved);
        RenderParams.Device->GetTransform(D3DTS_VIEW, &viewMatrixSaved);
        RenderParams.Device->GetTransform(D3DTS_PROJECTION, &projectionMatrixSaved);
        RenderParams.Device->GetTransform(D3DTS_TEXTURE0, &texture0MatrixSaved);

        Ptr<IDirect3DVertexShader9> pVertexShaderSaved;
        RenderParams.Device->GetVertexShader(&pVertexShaderSaved.GetRawRef());

        Ptr<IDirect3DPixelShader9> pPixelShaderSaved;
        RenderParams.Device->GetPixelShader(&pPixelShaderSaved.GetRawRef());

        D3DVIEWPORT9 viewportSaved;
        RenderParams.Device->GetViewport(&viewportSaved);

        Ptr<IDirect3DSurface9> pRenderTargetSaved;
        RenderParams.Device->GetRenderTarget(0, &pRenderTargetSaved.GetRawRef());


        // Load the graphics if not loaded already.
        if(!pTexture)
            LoadGraphics();

        // Calculate ortho projection.
        GetOrthoProjection(RenderState, OrthoProjection);

        HRESULT hResult = RenderParams.Device->BeginScene();
        if(FAILED(hResult))
            { HSWDISPLAY_LOG(("[HSWDisplay D3D9] BeginScene failed. %d (%x)", hResult, hResult)); }

        Ptr<IDirect3DSurface9> pDestSurface;
        hResult = eyeTextureD3D9->D3D9.pTexture->GetSurfaceLevel(0, &pDestSurface.GetRawRef());
        if(FAILED(hResult))
            { HSWDISPLAY_LOG(("[HSWDisplay D3D9] GetSurfaceLevel failed. %d (%x)", hResult, hResult)); }

        hResult = RenderParams.Device->SetRenderTarget(0, pDestSurface);
        if(FAILED(hResult))
            { HSWDISPLAY_LOG(("[HSWDisplay D3D9] SetRenderTarget failed. %d (%x)", hResult, hResult)); }

        D3DVIEWPORT9 D3DViewport;
        D3DViewport.X        = eyeTextureD3D9->Texture.Header.RenderViewport.Pos.x;
        D3DViewport.Y        = eyeTextureD3D9->Texture.Header.RenderViewport.Pos.y;    
        D3DViewport.Width    = eyeTextureD3D9->Texture.Header.RenderViewport.Size.w;
        D3DViewport.Height   = eyeTextureD3D9->Texture.Header.RenderViewport.Size.h;
        D3DViewport.MinZ     = 0;
        D3DViewport.MaxZ     = 1;
        hResult = RenderParams.Device->SetViewport(&D3DViewport);
        if(FAILED(hResult))
            { HSWDISPLAY_LOG(("[HSWDisplay D3D9] SetViewport failed. %d (%x)", hResult, hResult)); }

        hResult = RenderParams.Device->SetTexture(0, pTexture);
        if(FAILED(hResult))
            { HSWDISPLAY_LOG(("[HSWDisplay D3D9] SetTexture failed. %d (%x)", hResult, hResult)); }

        RenderParams.Device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
        RenderParams.Device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
        RenderParams.Device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);

        RenderParams.Device->SetVertexShader(NULL);
        RenderParams.Device->SetPixelShader(NULL);

        hResult = RenderParams.Device->SetStreamSource(0, pVB, 0, sizeof(HASWVertex));
        if(FAILED(hResult))
            { HSWDISPLAY_LOG(("[HSWDisplay D3D9] SetStreamSource failed. %d (%x)", hResult, hResult)); }

        RenderParams.Device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
        RenderParams.Device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
		RenderParams.Device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
        RenderParams.Device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
		RenderParams.Device->SetRenderState(D3DRS_LIGHTING, FALSE);
        RenderParams.Device->SetRenderState(D3DRS_ZENABLE, FALSE);
        RenderParams.Device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);
        RenderParams.Device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
        RenderParams.Device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
        RenderParams.Device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

        const float scale  = HSWDISPLAY_SCALE * ((RenderState.OurHMDInfo.HmdType == HmdType_DK1) ? 0.70f : 1.f);
        Matrix4f identityMatrix = Matrix4f::Identity();
        Vector3f translation = OrthoProjection[eye].GetTranslation();
        Matrix4f orthoStereoMatrix(
            scale, 0, 0, 0,
            0, scale / 2, 0, 0,
            0, 0, HSWDISPLAY_DISTANCE, 0,
            translation.x, translation.y, translation.z, 1
            );
        RenderParams.Device->SetTransform(D3DTS_WORLD,      reinterpret_cast<const D3DMATRIX*>(&identityMatrix));
        RenderParams.Device->SetTransform(D3DTS_VIEW,       reinterpret_cast<const D3DMATRIX*>(&identityMatrix));
        RenderParams.Device->SetTransform(D3DTS_PROJECTION, reinterpret_cast<const D3DMATRIX*>(&orthoStereoMatrix));
        RenderParams.Device->SetTransform(D3DTS_TEXTURE0,   reinterpret_cast<const D3DMATRIX*>(&identityMatrix));

        hResult = RenderParams.Device->SetFVF(HASWVertexD3D9Format);
        if(FAILED(hResult))
            { HSWDISPLAY_LOG(("[HSWDisplay D3D9] SetFVF failed. %d (%x)", hResult, hResult)); }

        hResult = RenderParams.Device->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
        if(FAILED(hResult))
            { HSWDISPLAY_LOG(("[HSWDisplay D3D9] DrawPrimitive failed. %d (%x)", hResult, hResult)); }

        hResult = RenderParams.Device->EndScene();
        if(FAILED(hResult))
            { HSWDISPLAY_LOG(("[HSWDisplay D3D9] EndScene failed. %d (%x)", hResult, hResult)); }


        // Restore previous state.
        RenderParams.Device->SetRenderTarget(0, pRenderTargetSaved);
        RenderParams.Device->SetViewport(&viewportSaved);
        RenderParams.Device->SetPixelShader(pPixelShaderSaved);
        RenderParams.Device->SetVertexShader(pVertexShaderSaved);
        RenderParams.Device->SetTransform(D3DTS_TEXTURE0, &texture0MatrixSaved);
        RenderParams.Device->SetTransform(D3DTS_PROJECTION, &projectionMatrixSaved);
        RenderParams.Device->SetTransform(D3DTS_VIEW, &viewMatrixSaved);
        RenderParams.Device->SetTransform(D3DTS_WORLD, &worldMatrixSaved);
        RenderParams.Device->SetTexture(0, pTexture0Saved);
        RenderParams.Device->SetTexture(1, pTexture1Saved);
        RenderParams.Device->SetStreamSource(0, pVBDSaved, vbOffsetSaved, vbStrideSaved);
        RenderParams.Device->SetFVF(fvfSaved);
    }
}