From 50af927de61b3fd22ab5e256f83c71be7063db06 Mon Sep 17 00:00:00 2001
From: Themaister <maister@archlinux.us>
Date: Fri, 29 Mar 2013 02:50:42 +0100
Subject: [PATCH] Add depth/stencil buffers to HW GL.

---
 gfx/gl.c                         | 69 +++++++++++++++++++++++++++++++-
 gfx/gl_common.h                  |  4 ++
 libretro-test-gl/libretro-test.c | 36 ++++++++++++-----
 libretro.h                       |  2 +
 4 files changed, 100 insertions(+), 11 deletions(-)

diff --git a/gfx/gl.c b/gfx/gl.c
index 3807c9ef6e..897f21e37b 100644
--- a/gfx/gl.c
+++ b/gfx/gl.c
@@ -135,6 +135,11 @@ static PFNGLBINDFRAMEBUFFERPROC pglBindFramebuffer;
 static PFNGLFRAMEBUFFERTEXTURE2DPROC pglFramebufferTexture2D;
 static PFNGLCHECKFRAMEBUFFERSTATUSPROC pglCheckFramebufferStatus;
 static PFNGLDELETEFRAMEBUFFERSPROC pglDeleteFramebuffers;
+static PFNGLGENRENDERBUFFERSPROC pglGenRenderbuffers;
+static PFNGLBINDRENDERBUFFERPROC pglBindRenderbuffer;
+static PFNGLFRAMEBUFFERRENDERBUFFERPROC pglFramebufferRenderbuffer;
+static PFNGLRENDERBUFFERSTORAGEPROC pglRenderbufferStorage;
+static PFNGLDELETERENDERBUFFERSPROC pglDeleteRenderbuffers;
 
 static bool load_fbo_proc(gl_t *gl)
 {
@@ -143,9 +148,17 @@ static bool load_fbo_proc(gl_t *gl)
    LOAD_GL_SYM(FramebufferTexture2D);
    LOAD_GL_SYM(CheckFramebufferStatus);
    LOAD_GL_SYM(DeleteFramebuffers);
+   LOAD_GL_SYM(GenRenderbuffers);
+   LOAD_GL_SYM(BindRenderbuffer);
+   LOAD_GL_SYM(FramebufferRenderbuffer);
+   LOAD_GL_SYM(RenderbufferStorage);
+   LOAD_GL_SYM(DeleteRenderbuffers);
 
    return pglGenFramebuffers && pglBindFramebuffer && pglFramebufferTexture2D && 
-      pglCheckFramebufferStatus && pglDeleteFramebuffers;
+      pglCheckFramebufferStatus && pglDeleteFramebuffers &&
+      pglGenRenderbuffers && pglBindRenderbuffer &&
+      pglFramebufferRenderbuffer && pglRenderbufferStorage &&
+      pglDeleteRenderbuffers;
 }
 #elif defined(HAVE_OPENGLES2)
 #define pglGenFramebuffers glGenFramebuffers
@@ -153,6 +166,11 @@ static bool load_fbo_proc(gl_t *gl)
 #define pglFramebufferTexture2D glFramebufferTexture2D
 #define pglCheckFramebufferStatus glCheckFramebufferStatus
 #define pglDeleteFramebuffers glDeleteFramebuffers
+#define pglGenRenderbuffers glGenRenderbuffers
+#define pglBindRenderbuffer glBindRenderbuffer
+#define pglFramebufferRenderbuffer glFramebufferRenderbuffer
+#define pglRenderbufferStorage glRenderbufferStorage
+#define pglDeleteRenderbuffers glDeleteRenderbuffers
 #define load_fbo_proc(gl) (true)
 #elif defined(HAVE_OPENGLES)
 #define pglGenFramebuffers glGenFramebuffersOES
@@ -160,6 +178,11 @@ static bool load_fbo_proc(gl_t *gl)
 #define pglFramebufferTexture2D glFramebufferTexture2DOES
 #define pglCheckFramebufferStatus glCheckFramebufferStatusOES
 #define pglDeleteFramebuffers glDeleteFramebuffersOES
+#define pglGenRenderbuffers glGenRenderbuffersOES
+#define pglBindRenderbuffer glBindRenderbufferOES
+#define pglFramebufferRenderbuffer glFramebufferRenderbufferOES
+#define pglRenderbufferStorage glRenderbufferStorageOES
+#define pglDeleteRenderbuffers glDeleteRenderbuffersOES
 #define GL_FRAMEBUFFER GL_FRAMEBUFFER_OES
 #define GL_COLOR_ATTACHMENT0 GL_COLOR_ATTACHMENT0_EXT
 #define GL_FRAMEBUFFER_COMPLETE GL_FRAMEBUFFER_COMPLETE_OES
@@ -170,6 +193,11 @@ static bool load_fbo_proc(gl_t *gl)
 #define pglFramebufferTexture2D glFramebufferTexture2D
 #define pglCheckFramebufferStatus glCheckFramebufferStatus
 #define pglDeleteFramebuffers glDeleteFramebuffers
+#define pglGenRenderbuffers glGenRenderbuffers
+#define pglBindRenderbuffer glBindRenderbuffer
+#define pglFramebufferRenderbuffer glFramebufferRenderbuffer
+#define pglRenderbufferStorage glRenderbufferStorage
+#define pglDeleteRenderbuffers glDeleteRenderbuffers
 #define load_fbo_proc(gl) (true)
 #endif
 #endif
@@ -710,10 +738,44 @@ bool gl_init_hw_render(gl_t *gl, unsigned width, unsigned height)
    glBindTexture(GL_TEXTURE_2D, 0);
    pglGenFramebuffers(TEXTURES, gl->hw_render_fbo);
 
+   bool depth   = g_extern.system.hw_render_callback.depth;
+   bool stencil = g_extern.system.hw_render_callback.stencil;
+
+   if (depth)
+   {
+      pglGenRenderbuffers(TEXTURES, gl->hw_render_depth);
+      gl->hw_render_depth_init = true;
+   }
+
+   if (stencil)
+   {
+      pglGenRenderbuffers(TEXTURES, gl->hw_render_stencil);
+      gl->hw_render_stencil_init = true;
+   }
+
    for (unsigned i = 0; i < TEXTURES; i++)
    {
       pglBindFramebuffer(GL_FRAMEBUFFER, gl->hw_render_fbo[i]);
       pglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gl->texture[i], 0);
+
+      if (depth)
+      {
+         pglBindRenderbuffer(GL_RENDERBUFFER, gl->hw_render_depth[i]);
+         pglRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
+               width, height);
+         pglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+               GL_RENDERBUFFER, gl->hw_render_depth[i]);
+      }
+
+      if (stencil)
+      {
+         pglBindRenderbuffer(GL_RENDERBUFFER, gl->hw_render_stencil[i]);
+         pglRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8,
+               width, height);
+         pglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+               GL_RENDERBUFFER, gl->hw_render_stencil[i]);
+      }
+
       GLenum status = pglCheckFramebufferStatus(GL_FRAMEBUFFER);
       if (status != GL_FRAMEBUFFER_COMPLETE)
       {
@@ -723,6 +785,7 @@ bool gl_init_hw_render(gl_t *gl, unsigned width, unsigned height)
    }
 
    pglBindFramebuffer(GL_FRAMEBUFFER, 0);
+   pglBindRenderbuffer(GL_RENDERBUFFER, 0);
    gl->hw_render_fbo_init = true;
    return true;
 }
@@ -1593,6 +1656,10 @@ static void gl_free(void *data)
 
    if (gl->hw_render_fbo_init)
       pglDeleteFramebuffers(TEXTURES, gl->hw_render_fbo);
+   if (gl->hw_render_depth)
+      pglDeleteRenderbuffers(TEXTURES, gl->hw_render_depth);
+   if (gl->hw_render_stencil)
+      pglDeleteRenderbuffers(TEXTURES, gl->hw_render_stencil);
    gl->hw_render_fbo_init = false;
 #endif
 
diff --git a/gfx/gl_common.h b/gfx/gl_common.h
index 814ba5611e..5160a17611 100644
--- a/gfx/gl_common.h
+++ b/gfx/gl_common.h
@@ -244,7 +244,11 @@ typedef struct gl
    bool fbo_inited;
 
    GLuint hw_render_fbo[TEXTURES];
+   GLuint hw_render_depth[TEXTURES];
+   GLuint hw_render_stencil[TEXTURES];
    bool hw_render_fbo_init;
+   bool hw_render_depth_init;
+   bool hw_render_stencil_init;
 #endif
 
    bool should_resize;
diff --git a/libretro-test-gl/libretro-test.c b/libretro-test-gl/libretro-test.c
index 54f6ddd838..5c835f4ba3 100644
--- a/libretro-test-gl/libretro-test.c
+++ b/libretro-test-gl/libretro-test.c
@@ -218,10 +218,12 @@ void retro_run(void)
    pglBindFramebuffer(GL_FRAMEBUFFER, hw_render.get_current_framebuffer());
    glClearColor(0.3, 0.4, 0.5, 1.0);
    glViewport(0, 0, 512, 512);
-   glClear(GL_COLOR_BUFFER_BIT);
+   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
    pglUseProgram(prog);
 
+   glEnable(GL_DEPTH_TEST);
+
    int loc = pglGetUniformLocation(prog, "uMVP");
 
    static unsigned frame_count;
@@ -230,15 +232,6 @@ void retro_run(void)
    float cos_angle = cos(angle);
    float sin_angle = sin(angle);
 
-   const GLfloat mvp[] = {
-      cos_angle, -sin_angle, 0, 0,
-      sin_angle, cos_angle, 0, 0,
-      0, 0, 1, 0,
-      0, 0, 0, 1,
-   };
-
-   pglUniformMatrix4fv(loc, 1, GL_FALSE, mvp);
-
    int vloc = pglGetAttribLocation(prog, "aVertex");
    pglVertexAttribPointer(vloc, 2, GL_FLOAT, GL_FALSE, 0, vertex);
    pglEnableVertexAttribArray(vloc);
@@ -246,7 +239,28 @@ void retro_run(void)
    pglVertexAttribPointer(cloc, 4, GL_FLOAT, GL_FALSE, 0, color);
    pglEnableVertexAttribArray(cloc);
 
+   const GLfloat mvp[] = {
+      cos_angle, -sin_angle, 0, 0,
+      sin_angle, cos_angle, 0, 0,
+      0, 0, 1, 0,
+      0, 0, 0, 1,
+   };
+   pglUniformMatrix4fv(loc, 1, GL_FALSE, mvp);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+   cos_angle *= 0.5;
+   sin_angle *= 0.5;
+   const GLfloat mvp2[] = {
+      cos_angle, -sin_angle, 0, 0.0,
+      sin_angle, cos_angle, 0, 0.0,
+      0, 0, 1, 0,
+      0.4, 0.4, 0.2, 1,
+   };
+
+   pglUniformMatrix4fv(loc, 1, GL_FALSE, mvp2);
+   glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+
    pglUseProgram(0);
    pglDisableVertexAttribArray(vloc);
    pglDisableVertexAttribArray(cloc);
@@ -274,6 +288,8 @@ bool retro_load_game(const struct retro_game_info *info)
 
    hw_render.context_type = RETRO_HW_CONTEXT_OPENGL;
    hw_render.context_reset = context_reset;
+   hw_render.depth = true;
+   hw_render.stencil = true;
    if (!environ_cb(RETRO_ENVIRONMENT_SET_HW_RENDER, &hw_render))
       return false;
 
diff --git a/libretro.h b/libretro.h
index 048bed8fbe..e710337ce6 100755
--- a/libretro.h
+++ b/libretro.h
@@ -462,6 +462,8 @@ struct retro_hw_render_callback
    retro_hw_context_reset_t context_reset; // Set by libretro core.
    retro_hw_get_current_framebuffer_t get_current_framebuffer; // Set by frontend.
    retro_hw_get_proc_address_t get_proc_address; // Set by frontend.
+   bool depth; // Set if render buffers should have depth component attached.
+   bool stencil; // Set if render buffers should have stencil component attached.
 };
 
 // Callback type passed in RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK. Called by the frontend in response to keyboard events.