DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/hardware/voodoo_vogl.cpp
00001 /*
00002  *  Copyright (C) 2002-2020  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License along
00015  *  with this program; if not, write to the Free Software Foundation, Inc.,
00016  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 // Tell Mac OS X to shut up about deprecated OpenGL calls
00020 #ifndef GL_SILENCE_DEPRECATION
00021 #define GL_SILENCE_DEPRECATION
00022 #endif
00023 
00024 #include <stdlib.h>
00025 #include <math.h>
00026 #include <map>
00027 
00028 #include "dosbox.h"
00029 #include "dos_inc.h"
00030 
00031 #if C_OPENGL
00032 
00033 #include "voodoo_vogl.h"
00034 
00035 /* NTS: This causes errors in Linux because MesaGL already defines these */
00036 #ifdef WIN32
00037 PFNGLMULTITEXCOORD4FVARBPROC __glMultiTexCoord4fvARB = NULL;
00038 PFNGLMULTITEXCOORD4FARBPROC __glMultiTexCoord4fARB = NULL;
00039 PFNGLACTIVETEXTUREARBPROC __glActiveTextureARB = NULL;
00040 #endif
00041 
00042 PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB = NULL;
00043 PFNGLSHADERSOURCEARBPROC glShaderSourceARB = NULL;
00044 PFNGLCOMPILESHADERARBPROC glCompileShaderARB = NULL;
00045 PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB = NULL;
00046 PFNGLATTACHOBJECTARBPROC glAttachObjectARB = NULL;
00047 PFNGLLINKPROGRAMARBPROC glLinkProgramARB = NULL;
00048 PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB = NULL;
00049 PFNGLUNIFORM1IARBPROC glUniform1iARB = NULL;
00050 PFNGLUNIFORM1FARBPROC glUniform1fARB = NULL;
00051 PFNGLUNIFORM2FARBPROC glUniform2fARB = NULL;
00052 PFNGLUNIFORM3FARBPROC glUniform3fARB = NULL;
00053 PFNGLUNIFORM4FARBPROC glUniform4fARB = NULL;
00054 PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB = NULL;
00055 PFNGLDETACHOBJECTARBPROC glDetachObjectARB = NULL;
00056 PFNGLDELETEOBJECTARBPROC glDeleteObjectARB = NULL;
00057 PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB = NULL;
00058 PFNGLGETINFOLOGARBPROC glGetInfoLogARB = NULL;
00059 PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT = NULL;
00060 PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT = NULL;
00061 PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB = NULL;
00062 PFNGLVERTEXATTRIB1FARBPROC glVertexAttrib1fARB = NULL;
00063 
00064 
00065 static Bit32s opengl_version = -1;
00066 
00067 static bool has_shaders = false;
00068 static bool has_stencil = false;
00069 static bool has_alpha = false;
00070 
00071 
00072 static INT32 current_begin_mode = -1;
00073 
00074 static Bit32s current_depth_mode = -1;
00075 static Bit32s current_depth_func = -1;
00076 
00077 static Bit32s current_alpha_enabled = -1;
00078 static Bit32s current_src_rgb_fac = -1;
00079 static Bit32s current_dst_rgb_fac = -1;
00080 static Bit32s current_src_alpha_fac = -1;
00081 static Bit32s current_dst_alpha_fac = -1;
00082 
00083 static bool depth_masked = false;
00084 static bool color_masked = false;
00085 static bool alpha_masked = false;
00086 
00087 // buffer read/write defaults are back-buffer for double buffered contexts
00088 static bool draw_to_front_buffer = false;
00089 static bool read_from_front_buffer = false;
00090 
00091 
00092 void VOGL_Reset(void) {
00093         opengl_version = -1;
00094         has_shaders = false;
00095         has_stencil = false;
00096         has_alpha = false;
00097 
00098         current_depth_mode=-1;
00099         current_depth_func=-1;
00100 
00101         current_alpha_enabled=-1;
00102         current_src_rgb_fac=-1;
00103         current_dst_rgb_fac=-1;
00104         current_src_alpha_fac=-1;
00105         current_dst_alpha_fac=-1;
00106 
00107         depth_masked = false;
00108         color_masked = false;
00109         alpha_masked = false;
00110 
00111         draw_to_front_buffer = false;
00112         read_from_front_buffer = false;
00113 }
00114 
00115 
00116 void VOGL_InitVersion(void) {
00117         opengl_version = -1;
00118 
00119         char gl_verstr[16];
00120         const GLubyte* gl_verstr_ub = glGetString(GL_VERSION);
00121         strncpy(gl_verstr, (const char*)gl_verstr_ub, 16);
00122         gl_verstr[15] = 0;
00123         char* gl_ver_minor = strchr(gl_verstr, '.');
00124         if (gl_ver_minor != NULL) {
00125                 gl_ver_minor++;
00126                 char* skip = strchr(gl_ver_minor, '.');
00127                 if (skip != NULL) *skip = 0;
00128         }
00129 
00130         int ogl_ver = 100;
00131         if (gl_verstr[0] != 0) {
00132                 int major = 1;
00133                 int minor = 0;
00134                 if (strchr(gl_verstr, '.') != NULL) {
00135                         if (sscanf(gl_verstr,"%d.%d", &major, &minor) != 2) major = 0;
00136                 } else {
00137                         if (sscanf(gl_verstr, "%d", &major) != 1) major = 0;
00138                 }
00139                 if (major > 0) {
00140                         ogl_ver = major*100;
00141                         if (minor >= 0) {
00142                                 if (minor < 10) ogl_ver += minor*10;
00143                                 else ogl_ver += minor;
00144                         }
00145                 }
00146         }
00147 
00148         if (ogl_ver > 0) opengl_version = ogl_ver;
00149 }
00150 
00151 void VOGL_ClearShaderFunctions(void) {
00152         glShaderSourceARB = NULL;
00153         glCompileShaderARB = NULL;
00154         glCreateProgramObjectARB = NULL;
00155         glAttachObjectARB = NULL;
00156         glLinkProgramARB = NULL;
00157         glUseProgramObjectARB = NULL;
00158         glUniform1iARB = NULL;
00159         glUniform1fARB = NULL;
00160         glUniform2fARB = NULL;
00161         glUniform3fARB = NULL;
00162         glUniform4fARB = NULL;
00163         glGetUniformLocationARB = NULL;
00164         glDetachObjectARB = NULL;
00165         glDeleteObjectARB  = NULL;
00166         glGetObjectParameterivARB = NULL;
00167         glGetInfoLogARB = NULL;
00168 }
00169 
00170 bool VOGL_Initialize(void) {
00171         VOGL_ClearShaderFunctions();
00172         
00173         VOGL_InitVersion();
00174 
00175 #ifdef WIN32
00176         __glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glActiveTextureARB"));
00177         if (!__glActiveTextureARB) {
00178                 LOG_MSG("opengl: glActiveTextureARB extension not supported");
00179                 return false;
00180         }
00181 
00182         __glMultiTexCoord4fARB = (PFNGLMULTITEXCOORD4FARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glMultiTexCoord4fARB"));
00183         if (!__glMultiTexCoord4fARB) {
00184                 LOG_MSG("opengl: glMultiTexCoord4fARB extension not supported");
00185                 return false;
00186         }
00187 
00188         __glMultiTexCoord4fvARB = (PFNGLMULTITEXCOORD4FVARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glMultiTexCoord4fvARB"));
00189         if (!__glMultiTexCoord4fvARB) {
00190                 LOG_MSG("opengl: glMultiTexCoord4fvARB extension not supported");
00191                 return false;
00192         }
00193 #endif
00194 
00195         glBlendFuncSeparateEXT = (PFNGLBLENDFUNCSEPARATEEXTPROC)((uintptr_t)SDL_GL_GetProcAddress("glBlendFuncSeparateEXT"));
00196         if (!glBlendFuncSeparateEXT) {
00197                 LOG_MSG("opengl: glBlendFuncSeparateEXT extension not supported");
00198                 return false;
00199         }
00200 
00201         glGenerateMipmapEXT = (PFNGLGENERATEMIPMAPEXTPROC)((uintptr_t)SDL_GL_GetProcAddress("glGenerateMipmapEXT"));
00202         if (!glGenerateMipmapEXT) {
00203                 LOG_MSG("opengl: glGenerateMipmapEXT extension not supported");
00204                 return false;
00205         }
00206 
00207         if (VOGL_CheckFeature(VOGL_ATLEAST_V20)) {
00208                 const char* extensions = (const char*)glGetString(GL_EXTENSIONS);
00209                 if (strstr(extensions, "GL_ARB_shader_objects") && strstr(extensions, "GL_ARB_vertex_shader") &&
00210                         strstr(extensions, "GL_ARB_fragment_shader")) {
00211 
00212                         glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glCreateShaderObjectARB"));
00213                         if (!glCreateShaderObjectARB) {
00214                                 LOG_MSG("opengl: shader extensions not supported. Using fixed pipeline");
00215                         } else {
00216                                 glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glShaderSourceARB"));
00217                                 if (!glShaderSourceARB) LOG_MSG("opengl: glShaderSourceARB extension not supported");
00218 
00219                                 glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glCompileShaderARB"));
00220                                 if (!glCompileShaderARB) LOG_MSG("opengl: glCompileShaderARB extension not supported");
00221 
00222                                 glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glCreateProgramObjectARB"));
00223                                 if (!glCreateProgramObjectARB) LOG_MSG("opengl: glCreateProgramObjectARB extension not supported");
00224 
00225                                 glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glAttachObjectARB"));
00226                                 if (!glAttachObjectARB) LOG_MSG("opengl: glAttachObjectARB extension not supported");
00227 
00228                                 glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glLinkProgramARB"));
00229                                 if (!glLinkProgramARB) LOG_MSG("opengl: glLinkProgramARB extension not supported");
00230 
00231                                 glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glUseProgramObjectARB"));
00232                                 if (!glUseProgramObjectARB) LOG_MSG("opengl: glUseProgramObjectARB extension not supported");
00233 
00234                                 glUniform1iARB = (PFNGLUNIFORM1IARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glUniform1iARB"));
00235                                 if (!glUniform1iARB) LOG_MSG("opengl: glUniform1iARB extension not supported");
00236 
00237                                 glUniform1fARB = (PFNGLUNIFORM1FARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glUniform1fARB"));
00238                                 if (!glUniform1fARB) LOG_MSG("opengl: glUniform1fARB extension not supported");
00239 
00240                                 glUniform2fARB = (PFNGLUNIFORM2FARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glUniform2fARB"));
00241                                 if (!glUniform2fARB) LOG_MSG("opengl: glUniform2fARB extension not supported");
00242 
00243                                 glUniform3fARB = (PFNGLUNIFORM3FARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glUniform3fARB"));
00244                                 if (!glUniform3fARB) LOG_MSG("opengl: glUniform3fARB extension not supported");
00245 
00246                                 glUniform4fARB = (PFNGLUNIFORM4FARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glUniform4fARB"));
00247                                 if (!glUniform4fARB) LOG_MSG("opengl: glUniform4fARB extension not supported");
00248 
00249                                 glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glGetUniformLocationARB"));
00250                                 if (!glGetUniformLocationARB) LOG_MSG("opengl: glGetUniformLocationARB extension not supported");
00251 
00252                                 glDetachObjectARB = (PFNGLDETACHOBJECTARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glDetachObjectARB"));
00253                                 if (!glDetachObjectARB) LOG_MSG("opengl: glDetachObjectARB extension not supported");
00254 
00255                                 glDeleteObjectARB  = (PFNGLDELETEOBJECTARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glDeleteObjectARB"));
00256                                 if (!glDeleteObjectARB) LOG_MSG("opengl: glDeleteObjectARB extension not supported");
00257 
00258                                 glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glGetObjectParameterivARB"));
00259                                 if (!glGetObjectParameterivARB) LOG_MSG("opengl: glGetObjectParameterivARB extension not supported");
00260 
00261                                 glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glGetInfoLogARB"));
00262                                 if (!glGetInfoLogARB) LOG_MSG("opengl: glGetInfoLogARB extension not supported");
00263 
00264                                 glGetAttribLocationARB = (PFNGLGETATTRIBLOCATIONARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glGetAttribLocationARB"));
00265                                 if (!glGetAttribLocationARB) LOG_MSG("opengl: glGetAttribLocationARB extension not supported");
00266                         
00267                                 glVertexAttrib1fARB = (PFNGLVERTEXATTRIB1FARBPROC)((uintptr_t)SDL_GL_GetProcAddress("glVertexAttrib1fARB"));
00268                                 if (!glVertexAttrib1fARB) LOG_MSG("opengl: glVertexAttrib1fARB extension not supported");
00269 
00270                                 if (glShaderSourceARB && glCompileShaderARB && glCreateProgramObjectARB &&
00271                                         glAttachObjectARB && glLinkProgramARB && glUseProgramObjectARB &&
00272                                         glUniform1iARB && glUniform1fARB && glUniform2fARB && glUniform3fARB &&
00273                                         glUniform4fARB && glGetUniformLocationARB && glDetachObjectARB &&
00274                                         glDeleteObjectARB && glGetObjectParameterivARB && glGetInfoLogARB) {
00275                                                 VOGL_FlagFeature(VOGL_HAS_SHADERS);
00276 //                                              LOG_MSG("opengl: shader functionality enabled");
00277                                 } else {
00278                                         VOGL_ClearShaderFunctions();
00279                                 }
00280                         }
00281                 }
00282         }
00283 
00284         LOG_MSG("opengl: I am able to use OpenGL to emulate Voodoo graphics");
00285         return true;
00286 }
00287 
00288 
00289 bool VOGL_CheckFeature(Bit32u feat) {
00290         switch (feat) {
00291                 case VOGL_ATLEAST_V20:
00292                         if (opengl_version >= 200) return true;
00293                         break;
00294                 case VOGL_ATLEAST_V21:
00295                         if (opengl_version >= 210) return true;
00296                         break;
00297                 case VOGL_ATLEAST_V30:
00298                         if (opengl_version >= 300) return true;
00299                         break;
00300                 case VOGL_HAS_SHADERS:
00301                         if (has_shaders) return true;
00302                         break;
00303                 case VOGL_HAS_STENCIL_BUFFER:
00304                         if (has_stencil) return true;
00305                         break;
00306                 case VOGL_HAS_ALPHA_PLANE:
00307                         if (has_alpha) return true;
00308                         break;
00309                 default:
00310                         LOG_MSG("opengl: unknown feature queried: %x",feat);
00311                         break;
00312         }
00313 
00314         return false;
00315 }
00316 
00317 void VOGL_FlagFeature(Bit32u feat) {
00318         switch (feat) {
00319                 case VOGL_HAS_SHADERS:
00320                         has_shaders = true;
00321                         break;
00322                 case VOGL_HAS_STENCIL_BUFFER:
00323                         has_stencil = true;
00324                         break;
00325                 case VOGL_HAS_ALPHA_PLANE:
00326                         has_alpha = true;
00327                         break;
00328                 default:
00329                         LOG_MSG("opengl: unknown feature: %x",feat);
00330                         break;
00331         }
00332 }
00333 
00334 
00335 void VOGL_BeginMode(INT32 new_mode) {
00336         if (current_begin_mode > -1) {
00337                 if (new_mode != current_begin_mode) {
00338                         glEnd();
00339                         if (new_mode > -1) glBegin((GLenum)new_mode);
00340                         current_begin_mode = new_mode;
00341                 }
00342         } else {
00343                 if (new_mode > -1) {
00344                         glBegin((GLenum)new_mode);
00345                         current_begin_mode = new_mode;
00346                 }
00347         }
00348 }
00349 
00350 void VOGL_ClearBeginMode(void) {
00351         if (current_begin_mode > -1) {
00352                 glEnd();
00353                 current_begin_mode = -1;
00354         }
00355 }
00356 
00357 
00358 void VOGL_SetDepthMode(Bit32s mode, Bit32s func) {
00359         if (current_depth_mode!=mode) {
00360                 if (mode!=0) {
00361                         VOGL_ClearBeginMode();
00362                         glEnable(GL_DEPTH_TEST);
00363                         current_depth_mode=1;
00364                         if (current_depth_func!=func) {
00365                                 glDepthFunc((GLenum)(GL_NEVER+func));
00366                                 current_depth_func=func;
00367                         }
00368                 } else {
00369                         VOGL_ClearBeginMode();
00370                         glDisable(GL_DEPTH_TEST);
00371                         current_depth_mode=0;
00372                 }
00373         } else {
00374                 if ((mode!=0) && (current_depth_func!=func)) {
00375                         VOGL_ClearBeginMode();
00376                         glDepthFunc((GLenum)(GL_NEVER+func));
00377                         current_depth_func=func;
00378                 }
00379         }
00380 }
00381 
00382 
00383 void VOGL_SetAlphaMode(Bit32s enabled_mode,GLuint src_rgb_fac,GLuint dst_rgb_fac,
00384                                                                                         GLuint src_alpha_fac,GLuint dst_alpha_fac) {
00385         if (current_alpha_enabled!=enabled_mode) {
00386                 VOGL_ClearBeginMode();
00387                 if (enabled_mode!=0) {
00388                         glEnable(GL_BLEND);
00389                         current_alpha_enabled=1;
00390                         if ((current_src_rgb_fac!=(Bit32s)src_rgb_fac) || (current_dst_rgb_fac!=(Bit32s)dst_rgb_fac) ||
00391                                 (current_src_alpha_fac!=(Bit32s)src_alpha_fac) || (current_dst_alpha_fac!=(Bit32s)dst_alpha_fac)) {
00392                                 glBlendFuncSeparateEXT(src_rgb_fac, dst_rgb_fac, src_alpha_fac, dst_alpha_fac);
00393                                 current_src_rgb_fac=(Bit32s)src_rgb_fac;
00394                                 current_dst_rgb_fac=(Bit32s)dst_rgb_fac;
00395                                 current_src_alpha_fac=(Bit32s)src_alpha_fac;
00396                                 current_dst_alpha_fac=(Bit32s)dst_alpha_fac;
00397                         }
00398                 } else {
00399                         glDisable(GL_BLEND);
00400                         current_alpha_enabled=0;
00401                 }
00402         } else {
00403                 if (current_alpha_enabled!=0) {
00404                         if ((current_src_rgb_fac!=(Bit32s)src_rgb_fac) || (current_dst_rgb_fac!=(Bit32s)dst_rgb_fac) ||
00405                                 (current_src_alpha_fac!=(Bit32s)src_alpha_fac) || (current_dst_alpha_fac!=(Bit32s)dst_alpha_fac)) {
00406                                 VOGL_ClearBeginMode();
00407                                 glBlendFuncSeparateEXT(src_rgb_fac, dst_rgb_fac, src_alpha_fac, dst_alpha_fac);
00408                                 current_src_rgb_fac=(Bit32s)src_rgb_fac;
00409                                 current_dst_rgb_fac=(Bit32s)dst_rgb_fac;
00410                                 current_src_alpha_fac=(Bit32s)src_alpha_fac;
00411                                 current_dst_alpha_fac=(Bit32s)dst_alpha_fac;
00412                         }
00413                 }
00414         }
00415 }
00416 
00417 
00418 void VOGL_SetDepthMaskMode(bool masked) {
00419         if (depth_masked!=masked) {
00420                 VOGL_ClearBeginMode();
00421                 if (masked) {
00422                         glDepthMask(GL_TRUE);
00423                         depth_masked=true;
00424                 } else {
00425                         glDepthMask(GL_FALSE);
00426                         depth_masked=false;
00427                 }
00428         }
00429 }
00430 
00431 
00432 void VOGL_SetColorMaskMode(bool cmasked, bool amasked) {
00433         if ((color_masked!=cmasked) || (alpha_masked!=amasked)) {
00434                 color_masked=cmasked;
00435                 alpha_masked=amasked;
00436                 GLboolean cm = (color_masked ? GL_TRUE : GL_FALSE);
00437                 GLboolean am = (alpha_masked ? GL_TRUE : GL_FALSE);
00438                 glColorMask(cm,cm,cm,am);
00439         }
00440 }
00441 
00442 
00443 void VOGL_SetDrawMode(bool front_draw) {
00444         if (draw_to_front_buffer!=front_draw) {
00445                 VOGL_ClearBeginMode();
00446                 if (front_draw) glDrawBuffer(GL_FRONT);
00447                 else glDrawBuffer(GL_BACK);
00448                 draw_to_front_buffer=front_draw;
00449         }
00450 }
00451 
00452 
00453 void VOGL_SetReadMode(bool front_read) {
00454         VOGL_ClearBeginMode();
00455 
00456         if (read_from_front_buffer!=front_read) {
00457                 if (front_read) glReadBuffer(GL_FRONT);
00458                 else glReadBuffer(GL_BACK);
00459                 read_from_front_buffer=front_read;
00460         }
00461 }
00462 
00463 #endif