3dfx Glide renderer (#800)
Some checks failed
CI / clang-format (push) Has been cancelled
CI / ${{ matrix.name }} (false, --toolchain $GITHUB_WORKSPACE/CMake/i586-pc-msdosdjgpp.cmake, false, true, false, Ninja, DOS, ubuntu-latest, true) (push) Has been cancelled
CI / ${{ matrix.name }} (false, --toolchain /usr/local/vitasdk/share/vita.toolchain.cmake, false, false, Ninja, Vita, ubuntu-latest, true, true) (push) Has been cancelled
CI / ${{ matrix.name }} (false, -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0.26100.0, false, false, Visual Studio 17 2022, true, Xbox One, windows-latest, amd64, false, true) (push) Has been cancelled
CI / ${{ matrix.name }} (false, -DCMAKE_TOOLCHAIN_FILE=/opt/devkitpro/cmake/3DS.cmake, false, devkitpro/devkitarm:latest, false, Ninja, true, Nintendo 3DS, ubuntu-latest, true) (push) Has been cancelled
CI / ${{ matrix.name }} (false, -DCMAKE_TOOLCHAIN_FILE=/opt/devkitpro/cmake/Switch.cmake, false, devkitpro/devkita64:latest, false, Ninja, Nintendo Switch, true, ubuntu-latest, true) (push) Has been cancelled
CI / ${{ matrix.name }} (false, emcmake, false, false, true, Ninja, Emscripten, ubuntu-latest, true) (push) Has been cancelled
CI / ${{ matrix.name }} (false, false, false, Ninja, true, MSVC (arm64), windows-latest, amd64_arm64, false) (push) Has been cancelled
CI / ${{ matrix.name }} (false, false, true, Ninja, true, MSVC (x86), windows-latest, amd64_x86, false) (push) Has been cancelled
CI / ${{ matrix.name }} (false, true, false, Ninja, true, MSVC (x64), windows-latest, amd64, false) (push) Has been cancelled
CI / ${{ matrix.name }} (false, true, true, false, Ninja, true, MSVC (x64 Debug), windows-latest, amd64, false) (push) Has been cancelled
CI / ${{ matrix.name }} (true, false, -DCMAKE_SYSTEM_NAME=iOS, false, false, Xcode, true, iOS, macos-15, true) (push) Has been cancelled
CI / ${{ matrix.name }} (true, false, false, false, Ninja, Android, ubuntu-latest, true) (push) Has been cancelled
CI / ${{ matrix.name }} (true, false, true, false, Ninja, macOS, macos-latest, true) (push) Has been cancelled
CI / ${{ matrix.name }} (true, true, false, Ninja, true, mingw-w64-x86_64, mingw64, msys2 mingw64, windows-latest, msys2 {0}, true) (push) Has been cancelled
CI / ${{ matrix.name }} (true, true, true, false, Ninja, true, Linux (Debug), ubuntu-latest, true) (push) Has been cancelled
CI / ${{ matrix.name }} (true, true, true, false, Ninja, true, Linux, ubuntu-latest, true) (push) Has been cancelled
CI / FreeBSD (push) Has been cancelled
CI / Flatpak (${{ matrix.arch }}) (aarch64, ubuntu-22.04-arm) (push) Has been cancelled
CI / Flatpak (${{ matrix.arch }}) (x86_64, ubuntu-latest) (push) Has been cancelled
CI / C++ (push) Has been cancelled
Docker / Publish web port (push) Has been cancelled
CI / Release (push) Has been cancelled

This commit is contained in:
Anders Jenbo 2026-05-04 21:30:03 +02:00 committed by GitHub
parent 9997e45fa0
commit 8c8559452d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 1833 additions and 0 deletions

View File

@ -90,6 +90,7 @@ cmake_dependent_option(ISLE_USE_LWS "Use libwebsockets for native multiplayer" O
cmake_dependent_option(ISLE_BUILD_CONFIG "Build CONFIG.EXE application" ON "MSVC OR ISLE_MINIWIN;NOT DOS;NOT NINTENDO_3DS;NOT NINTENDO_SWITCH;NOT WINDOWS_STORE;NOT VITA" OFF) cmake_dependent_option(ISLE_BUILD_CONFIG "Build CONFIG.EXE application" ON "MSVC OR ISLE_MINIWIN;NOT DOS;NOT NINTENDO_3DS;NOT NINTENDO_SWITCH;NOT WINDOWS_STORE;NOT VITA" OFF)
cmake_dependent_option(ISLE_COMPILE_SHADERS "Compile shaders" ON "SDL_SHADERCROSS_BIN;TARGET Python3::Interpreter" OFF) cmake_dependent_option(ISLE_COMPILE_SHADERS "Compile shaders" ON "SDL_SHADERCROSS_BIN;TARGET Python3::Interpreter" OFF)
cmake_dependent_option(CMAKE_POSITION_INDEPENDENT_CODE "Build with -fPIC" ON "NOT DOS;NOT VITA" OFF) cmake_dependent_option(CMAKE_POSITION_INDEPENDENT_CODE "Build with -fPIC" ON "NOT DOS;NOT VITA" OFF)
cmake_dependent_option(ISLE_USE_GLIDE "Build with 3dfx Glide support (Voodoo)" ON "DOS" OFF)
option(ENABLE_CLANG_TIDY "Enable clang-tidy") option(ENABLE_CLANG_TIDY "Enable clang-tidy")
option(DOWNLOAD_DEPENDENCIES "Download dependencies" ON) option(DOWNLOAD_DEPENDENCIES "Download dependencies" ON)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" CACHE PATH "Directory where to put executables and dll") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" CACHE PATH "Directory where to put executables and dll")
@ -103,6 +104,126 @@ if(DOS)
# (normally in libatomic, which DJGPP doesn't ship) are provided as simple # (normally in libatomic, which DJGPP doesn't ship) are provided as simple
# non-atomic stubs in 3rdparty/djgpp_atomic64.c since DOS is single-threaded. # non-atomic stubs in 3rdparty/djgpp_atomic64.c since DOS is single-threaded.
add_compile_options(-march=i486) add_compile_options(-march=i486)
if(ISLE_USE_GLIDE)
# 3dfx Glide support for Voodoo cards.
# See: https://federicotech.wordpress.com/2024/12/19/compiling-3dfx-glide-2-and-3-in-ms-dos-with-djgpp/
set(GLIDE_VERSION "3" CACHE STRING "Glide API version: 2 or 3")
set_property(CACHE GLIDE_VERSION PROPERTY STRINGS 2 3)
set(GLIDE_HW "sst1" CACHE STRING "Target Glide hardware: sst1 (Voodoo1), sst96 (Rush), cvg (Voodoo2), h3 (Banshee), h5 (Voodoo3/4/5)")
set_property(CACHE GLIDE_HW PROPERTY STRINGS sst1 sst96 cvg h3 h5)
include(FetchContent)
FetchContent_Declare(
glide
GIT_REPOSITORY "https://github.com/sezero/glide.git"
GIT_TAG "glide-devel-sezero"
)
FetchContent_MakeAvailable(glide)
set(GLIDE_SRC_DIR "${glide_SOURCE_DIR}")
if(GLIDE_VERSION STREQUAL "3")
set(GLIDE_ROOT "${GLIDE_SRC_DIR}/glide3x")
else()
set(GLIDE_ROOT "${GLIDE_SRC_DIR}/glide2x")
endif()
# Copy swlibs into glide dir (required by the build system)
if(NOT EXISTS "${GLIDE_ROOT}/swlibs")
file(COPY "${GLIDE_SRC_DIR}/swlibs" DESTINATION "${GLIDE_ROOT}")
endif()
# Patch fxglide.h for h3/h5 builds: the P6 fence inline asm check
# fails when HOST_CC is x86_64 gcc (no __i386__ defined).
foreach(_glide_hw_dir h3 h5)
set(_fxglide "${GLIDE_ROOT}/${_glide_hw_dir}/glide/src/fxglide.h")
if(EXISTS "${_fxglide}")
file(READ "${_fxglide}" _fxglide_content)
string(FIND "${_fxglide_content}" "defined(__x86_64__)" _already_patched)
if(_already_patched EQUAL -1)
string(REPLACE
"defined(__GNUC__) && defined(__i386__)"
"defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))"
_fxglide_content "${_fxglide_content}")
file(WRITE "${_fxglide}" "${_fxglide_content}")
endif()
endif()
endforeach()
# Determine include and lib paths based on hardware target
set(_glide_subdir "glide")
if(GLIDE_VERSION STREQUAL "3")
set(_glide_subdir "glide3")
endif()
if(GLIDE_HW STREQUAL "sst1" OR GLIDE_HW STREQUAL "sst96")
set(GLIDE_INCLUDE_DIR
"${GLIDE_ROOT}/swlibs/fxmisc"
"${GLIDE_ROOT}/sst1/${_glide_subdir}/src"
"${GLIDE_ROOT}/sst1/init"
)
set(GLIDE_LIB_DIR "${GLIDE_ROOT}/sst1/lib/${GLIDE_HW}")
elseif(GLIDE_HW STREQUAL "cvg")
set(GLIDE_INCLUDE_DIR
"${GLIDE_ROOT}/swlibs/fxmisc"
"${GLIDE_ROOT}/cvg/${_glide_subdir}/src"
"${GLIDE_ROOT}/cvg/incsrc"
)
set(GLIDE_LIB_DIR "${GLIDE_ROOT}/cvg/lib")
elseif(GLIDE_HW STREQUAL "h3")
set(GLIDE_INCLUDE_DIR
"${GLIDE_ROOT}/swlibs/fxmisc"
"${GLIDE_ROOT}/h3/${_glide_subdir}/src"
"${GLIDE_ROOT}/h3/incsrc"
)
set(GLIDE_LIB_DIR "${GLIDE_ROOT}/h3/lib")
elseif(GLIDE_HW STREQUAL "h5")
set(GLIDE_INCLUDE_DIR
"${GLIDE_ROOT}/swlibs/fxmisc"
"${GLIDE_ROOT}/h5/${_glide_subdir}/src"
"${GLIDE_ROOT}/h5/incsrc"
)
set(GLIDE_LIB_DIR "${GLIDE_ROOT}/h5/lib")
endif()
# Build Glide using its native DJGPP Makefile.
# We pass CC and AR from the CMake toolchain so it uses the correct cross-compiler.
if(GLIDE_VERSION STREQUAL "3")
set(_glide_lib_name "libgld3x.a")
set(_glide_lib_var "GLIDE_LIB=libgld3x.a")
set(_glide_imp_var "GLIDE_IMP=libgld3i.a")
else()
set(_glide_lib_name "libgld2x.a")
set(_glide_lib_var "GLIDE_LIB=libgld2x.a")
set(_glide_imp_var "GLIDE_IMP=libgld2i.a")
endif()
set(GLIDE_LIB_FILE "${GLIDE_LIB_DIR}/${_glide_lib_name}")
if(NOT EXISTS "${GLIDE_LIB_FILE}")
message(STATUS "Building 3dfx Glide ${GLIDE_VERSION}.x for ${GLIDE_HW}...")
execute_process(
COMMAND make
${_glide_lib_var}
${_glide_imp_var}
FX_GLIDE_HW=${GLIDE_HW}
CC=${CMAKE_C_COMPILER}
AR=${CMAKE_AR}
HOST_CC=gcc
-f Makefile.DJ
WORKING_DIRECTORY "${GLIDE_ROOT}"
RESULT_VARIABLE GLIDE_BUILD_RESULT
)
if(NOT GLIDE_BUILD_RESULT EQUAL 0)
message(FATAL_ERROR "Failed to build Glide library. "
"You may need to build manually: cd ${GLIDE_ROOT} && make ${_glide_lib_var} FX_GLIDE_HW=${GLIDE_HW} CC=${CMAKE_C_COMPILER} AR=${CMAKE_AR} -f Makefile.DJ")
endif()
endif()
if(NOT EXISTS "${GLIDE_LIB_FILE}")
message(FATAL_ERROR "Glide library not found at ${GLIDE_LIB_FILE} after build.")
endif()
set(GLIDE_LIBRARY "${GLIDE_LIB_FILE}")
message(STATUS "3dfx Glide: ${GLIDE_HW} (${GLIDE_LIBRARY})")
endif()
endif() endif()
message(STATUS "Isle app: ${ISLE_BUILD_APP}") message(STATUS "Isle app: ${ISLE_BUILD_APP}")

View File

@ -71,6 +71,15 @@ endif()
if(DOS) if(DOS)
list(REMOVE_ITEM GRAPHICS_BACKENDS USE_SDL_GPU USE_OPENGL1 USE_OPENGLES2) #USE_SDL_GPU list(REMOVE_ITEM GRAPHICS_BACKENDS USE_SDL_GPU USE_OPENGL1 USE_OPENGLES2) #USE_SDL_GPU
if(ISLE_USE_GLIDE)
target_sources(miniwin PRIVATE src/d3drm/backends/glide/renderer.cpp)
target_include_directories(miniwin PRIVATE ${GLIDE_INCLUDE_DIR})
target_link_libraries(miniwin PRIVATE ${GLIDE_LIBRARY})
if(GLIDE_VERSION STREQUAL "3")
target_compile_definitions(miniwin PRIVATE GLIDE3=1)
endif()
list(APPEND GRAPHICS_BACKENDS USE_GLIDE)
endif()
endif() endif()
list(APPEND GRAPHICS_BACKENDS USE_PALETTE_SW_RENDER) list(APPEND GRAPHICS_BACKENDS USE_PALETTE_SW_RENDER)

File diff suppressed because it is too large Load Diff

View File

@ -26,6 +26,9 @@
#ifdef USE_GXM #ifdef USE_GXM
#include "d3drmrenderer_gxm.h" #include "d3drmrenderer_gxm.h"
#endif #endif
#ifdef USE_GLIDE
#include "d3drmrenderer_glide.h"
#endif
Direct3DRMRenderer* CreateDirect3DRMRenderer( Direct3DRMRenderer* CreateDirect3DRMRenderer(
const IDirect3DMiniwin* d3d, const IDirect3DMiniwin* d3d,
@ -78,6 +81,11 @@ Direct3DRMRenderer* CreateDirect3DRMRenderer(
return GXMRenderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight, d3d->GetMSAASamples()); return GXMRenderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight, d3d->GetMSAASamples());
} }
#endif #endif
#ifdef USE_GLIDE
if (SDL_memcmp(guid, &GLIDE_GUID, sizeof(GUID)) == 0) {
return new Direct3DRMGlideRenderer(DDSDesc.dwWidth, DDSDesc.dwHeight);
}
#endif
#ifdef USE_PALETTE_SW_RENDER #ifdef USE_PALETTE_SW_RENDER
if (SDL_memcmp(guid, &PALETTE_SW_GUID, sizeof(GUID)) == 0) { if (SDL_memcmp(guid, &PALETTE_SW_GUID, sizeof(GUID)) == 0) {
return new Direct3DRMPaletteSWRenderer(DDSDesc.dwWidth, DDSDesc.dwHeight); return new Direct3DRMPaletteSWRenderer(DDSDesc.dwWidth, DDSDesc.dwHeight);
@ -112,6 +120,9 @@ void Direct3DRMRenderer_EnumDevices(const IDirect3DMiniwin* d3d, LPD3DENUMDEVICE
#ifdef USE_PALETTE_SW_RENDER #ifdef USE_PALETTE_SW_RENDER
Direct3DRMPaletteSW_EnumDevice(cb, ctx); Direct3DRMPaletteSW_EnumDevice(cb, ctx);
#endif #endif
#ifdef USE_GLIDE
Direct3DRMGlide_EnumDevice(cb, ctx);
#endif
#ifdef USE_GXM #ifdef USE_GXM
GXMRenderer_EnumDevice(cb, ctx); GXMRenderer_EnumDevice(cb, ctx);
#endif #endif

View File

@ -0,0 +1,135 @@
#pragma once
#include "d3drmrenderer.h"
#include "d3drmtexture_impl.h"
#include "ddraw_impl.h"
#include <pc.h>
extern "C"
{
#include <glide.h>
}
#ifdef GLIDE3
// Glide 3 uses custom vertex layout - define our own struct
struct GlideVertex {
float x, y; // screen coords
float ooz; // 65535/Z (for Z-buffering)
float oow; // 1/w (for perspective correction)
float r, g, b, a; // color (0-255)
float sow, tow; // texture coords (s/w, t/w)
};
#define GR_WDEPTHVALUE_FARTHEST 0xFFFF
#else
typedef GrVertex GlideVertex;
#endif
#include <vector>
// clang-format off
DEFINE_GUID(GLIDE_GUID, 0x682656F3, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08);
// clang-format on
struct GlideTextureEntry {
IDirect3DRMTexture* texture;
Uint32 version;
GrTexInfo info;
FxU32 startAddress;
int texW; // actual power-of-2 width uploaded to Glide
int texH; // actual power-of-2 height uploaded to Glide
Uint32 lastUsedFrame; // frame number when last drawn
};
struct GlideMeshEntry {
const MeshGroup* meshGroup;
Uint32 version;
bool flat;
// Cached flattened geometry (only populated for flat-shaded meshes)
std::vector<D3DRMVERTEX> flatVertices;
std::vector<uint16_t> flatIndices;
};
class Direct3DRMGlideRenderer : public Direct3DRMRenderer {
public:
Direct3DRMGlideRenderer(int width, int height);
~Direct3DRMGlideRenderer() override;
void PushLights(const SceneLight* lights, size_t count) override;
void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override;
void SetFrustumPlanes(const Plane* frustumPlanes) override;
Uint32 GetTextureId(IDirect3DRMTexture* texture, bool isUI = false, float scaleX = 0, float scaleY = 0) override;
Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override;
HRESULT BeginFrame() override;
void EnableTransparency() override;
void SubmitDraw(
DWORD meshId,
const D3DRMMATRIX4D& modelViewMatrix,
const D3DRMMATRIX4D& worldMatrix,
const D3DRMMATRIX4D& viewMatrix,
const Matrix3x3& normalMatrix,
const Appearance& appearance
) override;
HRESULT FinalizeFrame() override;
void Resize(int width, int height, const ViewportTransform& viewportTransform) override;
void Clear(float r, float g, float b) override;
void Flip() override;
void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) override;
void Download(SDL_Surface* target) override;
void SetDither(bool dither) override;
void SetPalette(SDL_Palette* palette) override;
private:
void EvictTextures();
std::vector<GlideTextureEntry> m_textureCache;
std::vector<GlideMeshEntry> m_meshCache;
std::vector<SceneLight> m_lights;
D3DRMMATRIX4D m_projection;
D3DVALUE m_frontClip;
D3DVALUE m_backClip;
Plane m_frustumPlanes[6];
std::vector<D3DRMVERTEX> m_transformedVertices;
std::vector<SDL_Color> m_litColors;
bool m_transparencyEnabled;
bool m_in3DMode = true;
FxU32 m_nextTextureAddress;
Uint32 m_frameCounter = 0;
SDL_Palette* m_palette = nullptr;
bool m_paletteUploaded = false;
#ifdef GLIDE3
FxU32 m_glideContext = 0;
#endif
};
inline static bool Direct3DRMGlide_DetectVoodoo()
{
// Scan PCI for 3dfx vendor ID (0x121A) without touching Glide
for (int bus = 0; bus < 4; ++bus) {
for (int dev = 0; dev < 32; ++dev) {
outportl(0xCF8, 0x80000000 | (bus << 16) | (dev << 11));
unsigned int reg = inportl(0xCFC);
if ((reg & 0xFFFF) == 0x121A) {
return true;
}
}
}
return false;
}
inline static void Direct3DRMGlide_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx)
{
if (!Direct3DRMGlide_DetectVoodoo()) {
return;
}
D3DDEVICEDESC halDesc = {};
D3DDEVICEDESC helDesc = {};
halDesc.dcmColorModel = D3DCOLOR_RGB;
halDesc.dwFlags = D3DDD_DEVICEZBUFFERBITDEPTH;
halDesc.dwDeviceZBufferBitDepth = DDBD_16;
halDesc.dwDeviceRenderBitDepth = DDBD_16;
halDesc.dpcTriCaps.dwTextureCaps = D3DPTEXTURECAPS_PERSPECTIVE;
halDesc.dpcTriCaps.dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND;
halDesc.dpcTriCaps.dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR;
EnumDevice(cb, ctx, "3dfx Glide", &halDesc, &helDesc, GLIDE_GUID);
}