Inside3D!
     

MH's Direct3D 8.1 Wrapper

 
Post new topic   Reply to topic    Inside3d Forums Forum Index -> Engine Programming
View previous topic :: View next topic  
Author Message
Baker



Joined: 14 Mar 2006
Posts: 1538

PostPosted: Fri Jul 16, 2010 4:56 am    Post subject: MH's Direct3D 8.1 Wrapper Reply with quote

Back in December 2009, MH released a Direct3D 8.1 that is easy to implement for most GLQuake engines (Example engines [6] site). Note: including an experimental EZQuake and my engine there are 8 working prototype engines using the wrapper.

[FitzQuake, Enhanced GLQuake, FuhQuake, ZQuake, Tomaz are the others.]

MH gave me and updated version of the wrapper lately from April and it is quite a bit faster.

I've been spending a bit of time lately sorting through things trying to isolate necessary and unnecessary changes in my own engine to optimize it and debug it.

Anyway, here is what is probably my final list of #ifdefs for the wrapper. I try to use detail that explains the exception ...

Code:
#ifdef DX8QUAKE
# define DX8QUAKE_NO_DIALOGS               // No "starting Quake type "dialogs for DX8QUAKE
# define DX8QUAKE_NO_8BIT                  // D3D8 wrapper didn't keep the 8bit support
# define DX8QUAKE_GET_GL_MAX_SIZE          // D3D8 wrapper obtains the maxsize from the video card
# define DX8QUAKE_CANNOT_DETECT_FULLSCREEN_BY_MODESTATE   // Detecting modestate == MS_FULLDIB isn't useful
# define DX8QUAKE_NO_BINDTEXFUNC           // SGIS/ancient GL pathway removal
# define DX8QUAKE_NO_GL_ZTRICK             // DX8QUAKE hates gl_ztrick; clear the buffers every time
# define DX8QUAKE_GL_READPIXELS_NO_RGBA    // Wrapper only supports GL_RGBA; not GL_RGBA like envmap command uses
#endif


Most of the things like lack of "ztrick" support, the inability to do glReadPixels as GL_RGBA or compatibility with ancient obsoleted BindTexFunc or lack of 8 bit support or the "starting Quake" dialog wouldn't interest anyone anyway.

I have 2 or 3 bugs I'm battling not related to the Direct3D 8.1 wrapper but I am getting very high frames per second.

After ridding the 2 or 3 bugs that annoying me, the dx8 version of my engine is near enough in performance to GL as to be able to replace its usage and the reliability is top notch.

[Part of me is wondering what it'd be like to use the wrapper on a non-Quake engine that uses OpenGL 1.2 or thereabouts.]
_________________
Tomorrow Never Dies. I feel this Tomorrow knocking on the door ...
Back to top
View user's profile Send private message
Baker



Joined: 14 Mar 2006
Posts: 1538

PostPosted: Fri Jul 16, 2010 5:24 am    Post subject: Reply with quote

Btw ... how complicated is it to implement the wrapper in an OpenGL 1.2 type of engine (like not DarkPlaces).

Here are the changes in JoeQuake:

1. Put #ifdef/#endif as indicated around this code in sys_win.c to get rid of the "Starting Quake" type of dialog or in this case the popup JoeQuake logo ...
Code:
#ifdef USEFAKEGL
   if (!(isDedicated = COM_CheckParm("-dedicated")))
   {
      hwnd_dialog = CreateDialog (hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, NULL);

      if (hwnd_dialog)
      {
         if (GetWindowRect(hwnd_dialog, &rect))
         {
            if (rect.left > (rect.top * 2))
            {
               SetWindowPos (hwnd_dialog, 0,
                  (rect.left / 2) - ((rect.right - rect.left) / 2),
                  rect.top, 0, 0,
                  SWP_NOZORDER | SWP_NOSIZE);
            }
         }

         ShowWindow (hwnd_dialog, SW_SHOWDEFAULT);
         UpdateWindow (hwnd_dialog);
         SetForegroundWindow (hwnd_dialog);
      }
   }#endif


2. Very important ... in vid_wgl.c (gl_vidnt.c in some engines) ...

Do this ...

Code:
#ifdef USEFAKEGL
      FakeSwapBuffers ();
#else
      SwapBuffers (maindc);
#endif


3. In quakedef.h near the very top like after #include <windows.h> add this ...

Code:
// we're using the fake gl wrapper
#define USEFAKEGL

// FAKEGL - switch include files
#ifndef USEFAKEGL
#include <gl/gl.h>
#include <GL/glu.h>
// switch your OpenGL libs to this so that you can more easily switch between configurations
#pragma comment (lib, "opengl32.lib")
#pragma comment (lib, "glu32.lib")
#else
#include "fakegl.h"
#endif


Then add the wrapper (gl_fakegl.c) to the project. Then probably remove opengl32.lib and glu32.lib from references in the project as the immediately above code will add them if needed.
_________________
Tomorrow Never Dies. I feel this Tomorrow knocking on the door ...
Back to top
View user's profile Send private message
mh



Joined: 12 Jan 2008
Posts: 909

PostPosted: Fri Jul 16, 2010 9:25 am    Post subject: Reply with quote

Baker wrote:
Btw ... how complicated is it to implement the wrapper in an OpenGL 1.2 type of engine (like not DarkPlaces).
It depends on how the engine handles it's OpenGL initialization really. Something like Quake II won't work at all without heavy rewriting of the engine, as it does a LoadLibrary on opengl32.dll, then GetProcAddress on all entry points, including the 1.0 and 1.1 entry points.

In theory the wrapper could be compiled into an opengl32.dll which could then be dropped into your game directory. It should work in just about all cases then, although it would need to be viewed as being more like the old 3DFX mini GLs where only the needed subset of full OpenGL was implemented.
_________________
DirectQ Engine - New release 1.8.666a, 9th August 2010
MHQuake Blog (General)
Direct3D 8 Quake Engines
Back to top
View user's profile Send private message Visit poster's website
Spike



Joined: 05 Nov 2004
Posts: 944
Location: UK

PostPosted: Fri Jul 16, 2010 9:48 am    Post subject: Reply with quote

SwapBuffers is not actually part of opengl32.dll
You'd need to replace more dlls than just the opengl-specific ones.

You can rewrite the program's import/export address tables at run time, of course...
_________________
What's a signature?
Back to top
View user's profile Send private message Visit poster's website
mh



Joined: 12 Jan 2008
Posts: 909

PostPosted: Fri Jul 16, 2010 10:15 am    Post subject: Reply with quote

SwapBuffers actually calls into wglSwapBuffers if you're running an OpenGL context so it's cool. Likewise all of the other GDI functions end up calling wgl versions.

It's very interesting if you put a dummy DLL called opengl32.dll into your game directory, monitor GetProcAddress calls, and watch what happens behind the scenes. You can dump the exports table from MS's opengl32.dll, implement all of the required functions as stubs in your own DLL, then run it in a debugger with breakpoints set so that you can get a good idea of how everything links up together.

Incidentally, the only reason that the "Starting Quake..." dialog was removed was so that it would compile clean with VS 2008. It can still be used otherwise if you want.

This is a valid replacement winquake.rc that will also work with VS 2008:

Code:
#include "resource.h"
#include <windows.h>

#ifndef IDC_STATIC
#define IDC_STATIC (-1)
#endif

IDI_ICON2               ICON    DISCARDABLE     "quake.ico"

IDD_DIALOG1 DIALOGEX 0, 0, 62, 21
STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | WS_POPUP
EXSTYLE WS_EX_TOOLWINDOW | WS_EX_CLIENTEDGE
FONT 16, "Times New Roman", 0, 0, 0x1
BEGIN
    CTEXT           "Starting Quake...",IDC_STATIC,4,6,54,8
END

_________________
DirectQ Engine - New release 1.8.666a, 9th August 2010
MHQuake Blog (General)
Direct3D 8 Quake Engines
Back to top
View user's profile Send private message Visit poster's website
mh



Joined: 12 Jan 2008
Posts: 909

PostPosted: Fri Jul 16, 2010 11:58 am    Post subject: Reply with quote

A note on performance and other characteristics of the wrapper

Direct3D is very sensitive to primitive batching. Previous versions of this wrapper (pre April 2010) didn't attempt to batch at all, and performance suffered as a result. In April 2010 I rewrote it to use batching everywhere, detecting state changes as they happen and beginning a new batch on every state change.

All batches use indexed primitives with 16-bit indexes and the triangle list primitive type, except for if the requested OpenGL primitive type is GL_TRIANGLES, in which case it will use an unindexed triangle list. Strips and fans don't exist in it at all.

In many cases this will get performance that comes close to (or occasionally exceeds) OpenGL (which seems to batch up polygons internally within the driver), but it's dependent on the data that it's fed. If it's given polygons that are not grouped by state (the worst offender is R_DrawSequentialPoly or anything similar to/derived from it) it won't be able to batch them, and we get performance drop off.

A further optimization would be to detect if hardware T&L is available and use a dynamic vertex buffer if so. This is the approach used by DirectQ, which batches very agressively, and is able to draw the entire first scene of start.bsp, including the status bar, in 24 draw calls. It may not be viable for use with the wrapper as feeding a dynamic vertex buffer with polygons that aren't grouped by state will slow things down further. Some reworking of the surface refresh (especially getting rid of R_DrawSequentialPoly - a thing of true evil - and grouping bmodel surfs by texture) would be definitely required before it would be worthwhile doing this. Alias models and everything else are probably OK to leave as they are, but GLQuake's default surface refresh (especially the multitexture path) is embarrassingly suboptimal, even for OpenGL.

The wrapper supports a subset of baseline OpenGL 1.1 (similar to the old 3DFX mini GL) with some extensions available. Multitexture is exported, but combine modes are not. This isn't because D3D can't do combine modes (it can, and it's API is considerably more sensible than OpenGL here) but rather because the OpenGL API introduced a heavy layer of complexity in implementing them which caused other things to break.

It doesn't attempt to do much in the way of parameter validation, assuming that your OpenGL code is at least reasonably correct to begin with. I'm not sure if this was a wise decision but it certainly helped to speed up the development process. It does mean that you should test and confirm correct operation using native OpenGL rather than relying on this, however.
_________________
DirectQ Engine - New release 1.8.666a, 9th August 2010
MHQuake Blog (General)
Direct3D 8 Quake Engines
Back to top
View user's profile Send private message Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    Inside3d Forums Forum Index -> Engine Programming All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2004 phpBB Group