diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 463ac90928..384306ed8e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -510,7 +510,8 @@ set( PLAT_WIN32_SOURCES win32/gl_sysfb.cpp win32/base_sysfb.cpp win32/win32basevideo.cpp - win32/win32glvideo.cpp) + win32/win32glvideo.cpp + win32/win32polyvideo.cpp) if (HAVE_VULKAN) set (PLAT_WIN32_SOURCES ${PLAT_WIN32_SOURCES} win32/win32vulkanvideo.cpp ) @@ -713,6 +714,7 @@ file( GLOB HEADER_FILES rendering/polyrenderer/math/*.h rendering/polyrenderer/drawers/*.h rendering/polyrenderer/scene/*.h + rendering/polyrenderer/backend/*.h rendering/hwrenderer/data/*.h rendering/hwrenderer/dynlights/*.h rendering/hwrenderer/models/*.h @@ -927,6 +929,14 @@ if (HAVE_VULKAN) set (FASTMATH_SOURCES ${FASTMATH_SOURCES} ${VULKAN_SOURCES}) endif() +set (POLYBACKEND_SOURCES + rendering/polyrenderer/backend/poly_framebuffer.cpp + rendering/polyrenderer/backend/poly_buffers.cpp + rendering/polyrenderer/backend/poly_hwtexture.cpp + rendering/polyrenderer/backend/poly_renderstate.cpp +) +set (FASTMATH_SOURCES ${FASTMATH_SOURCES} ${POLYBACKEND_SOURCES}) + set (PCH_SOURCES am_map.cpp b_bot.cpp @@ -1555,6 +1565,7 @@ source_group("Rendering\\Poly Renderer" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOU source_group("Rendering\\Poly Renderer\\Math" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/polyrenderer/math/.+") source_group("Rendering\\Poly Renderer\\Drawers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/polyrenderer/drawers/.+") source_group("Rendering\\Poly Renderer\\Scene" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/polyrenderer/scene/.+") +source_group("Rendering\\Poly Renderer\\Backend" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/rendering/polyrenderer/backend/.+") source_group("Render Data" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/r_data/.+") source_group("Render Data\\Models" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/r_data/models/.+") source_group("Render Interface" FILES r_defs.h r_renderer.h r_sky.cpp r_sky.h r_state.h r_utility.cpp r_utility.h) diff --git a/src/gamedata/textures/textures.h b/src/gamedata/textures/textures.h index 6f5e649fdd..5b12de3274 100644 --- a/src/gamedata/textures/textures.h +++ b/src/gamedata/textures/textures.h @@ -294,9 +294,11 @@ class FTexture friend class FMaterial; friend class OpenGLRenderer::FGLRenderState; // For now this needs access to some fields in ApplyMaterial. This should be rerouted through the Material class friend class VkRenderState; + friend class PolyRenderState; friend struct FTexCoordInfo; friend class OpenGLRenderer::FHardwareTexture; friend class VkHardwareTexture; + friend class PolyHardwareTexture; friend class FMultiPatchTexture; friend class FSkyBox; friend class FBrightmapTexture; diff --git a/src/rendering/polyrenderer/backend/poly_buffers.cpp b/src/rendering/polyrenderer/backend/poly_buffers.cpp new file mode 100644 index 0000000000..7ca4d17681 --- /dev/null +++ b/src/rendering/polyrenderer/backend/poly_buffers.cpp @@ -0,0 +1,131 @@ + +#include "poly_buffers.h" +#include "poly_framebuffer.h" +#include "poly_renderstate.h" +#include "doomerrors.h" + +PolyBuffer *PolyBuffer::First = nullptr; + +PolyBuffer::PolyBuffer() +{ + Next = First; + First = this; + if (Next) Next->Prev = this; +} + +PolyBuffer::~PolyBuffer() +{ + if (Next) Next->Prev = Prev; + if (Prev) Prev->Next = Next; + else First = Next; +} + +void PolyBuffer::ResetAll() +{ + for (PolyBuffer *cur = PolyBuffer::First; cur; cur = cur->Next) + cur->Reset(); +} + +void PolyBuffer::Reset() +{ +} + +void PolyBuffer::SetData(size_t size, const void *data, bool staticdata) +{ + mData.resize(size); + map = mData.data(); + if (data) + memcpy(map, data, size); + buffersize = size; +} + +void PolyBuffer::SetSubData(size_t offset, size_t size, const void *data) +{ + memcpy(static_cast(map) + offset, data, size); +} + +void PolyBuffer::Resize(size_t newsize) +{ + mData.resize(newsize); + buffersize = newsize; + map = mData.data(); +} + +void PolyBuffer::Map() +{ +} + +void PolyBuffer::Unmap() +{ +} + +void *PolyBuffer::Lock(unsigned int size) +{ + return map; +} + +void PolyBuffer::Unlock() +{ +} + +///////////////////////////////////////////////////////////////////////////// + +void PolyVertexBuffer::SetFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs) +{ + for (int j = 0; j < numAttributes; j++) + { + mOffsets[attrs[j].location] = attrs[j].offset; + } + mStride = stride; +} + +void PolyVertexBuffer::CopyVertices(TriVertex *dst, int count, int index) +{ + size_t stride = mStride; + size_t offsetVertex = mOffsets[VATTR_VERTEX]; + size_t offsetTexcoord = mOffsets[VATTR_TEXCOORD]; + uint8_t *vertex = static_cast(map) + stride * index; + + for (int i = 0; i < count; i++) + { + dst[i].x = *reinterpret_cast(vertex + offsetVertex); + dst[i].y = *reinterpret_cast(vertex + offsetVertex + 4); + dst[i].z = *reinterpret_cast(vertex + offsetVertex + 8); + dst[i].w = 1.0f; + dst[i].v = *reinterpret_cast(vertex + offsetTexcoord); + dst[i].u = *reinterpret_cast(vertex + offsetTexcoord + 4); + vertex += stride; + } +} + +void PolyVertexBuffer::CopyIndexed(TriVertex *dst, uint32_t *elements, int count, int index) +{ + size_t stride = mStride; + size_t offsetVertex = mOffsets[VATTR_VERTEX]; + size_t offsetTexcoord = mOffsets[VATTR_TEXCOORD]; + uint8_t *vertices = static_cast(map); + + elements += index; + for (int i = 0; i < count; i++) + { + uint8_t *vertex = vertices + stride * elements[i]; + dst[i].x = *reinterpret_cast(vertex + offsetVertex); + dst[i].y = *reinterpret_cast(vertex + offsetVertex + 4); + dst[i].z = *reinterpret_cast(vertex + offsetVertex + 8); + dst[i].w = 1.0f; + dst[i].v = *reinterpret_cast(vertex + offsetTexcoord); + dst[i].u = *reinterpret_cast(vertex + offsetTexcoord + 4); + } +} + +///////////////////////////////////////////////////////////////////////////// + +void PolyDataBuffer::BindRange(size_t start, size_t length) +{ + GetPolyFrameBuffer()->GetRenderState()->Bind(this, (uint32_t)start, (uint32_t)length); +} + +void PolyDataBuffer::BindBase() +{ + GetPolyFrameBuffer()->GetRenderState()->Bind(this, 0, (uint32_t)buffersize); +} diff --git a/src/rendering/polyrenderer/backend/poly_buffers.h b/src/rendering/polyrenderer/backend/poly_buffers.h new file mode 100644 index 0000000000..49375c7d04 --- /dev/null +++ b/src/rendering/polyrenderer/backend/poly_buffers.h @@ -0,0 +1,72 @@ +#pragma once + +#include "hwrenderer/data/buffers.h" +#include "utility/tarray.h" +#include + +#ifdef _MSC_VER +// silence bogus warning C4250: 'PolyVertexBuffer': inherits 'PolyBuffer::PolyBuffer::SetData' via dominance +// According to internet infos, the warning is erroneously emitted in this case. +#pragma warning(disable:4250) +#endif + +struct TriVertex; + +class PolyBuffer : virtual public IBuffer +{ +public: + PolyBuffer(); + ~PolyBuffer(); + + static void ResetAll(); + void Reset(); + + void SetData(size_t size, const void *data, bool staticdata) override; + void SetSubData(size_t offset, size_t size, const void *data) override; + void Resize(size_t newsize) override; + + void Map() override; + void Unmap() override; + + void *Lock(unsigned int size) override; + void Unlock() override; + +private: + static PolyBuffer *First; + PolyBuffer *Prev = nullptr; + PolyBuffer *Next = nullptr; + std::vector mData; +}; + +class PolyVertexBuffer : public IVertexBuffer, public PolyBuffer +{ +public: + PolyVertexBuffer() { } + void SetFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs) override; + + void CopyVertices(TriVertex *dst, int count, int index); + void CopyIndexed(TriVertex *dst, uint32_t *elements, int count, int index); + +private: + size_t mOffsets[VATTR_MAX] = {}; + size_t mStride = 0; +}; + +class PolyIndexBuffer : public IIndexBuffer, public PolyBuffer +{ +public: + PolyIndexBuffer() { } +}; + +class PolyDataBuffer : public IDataBuffer, public PolyBuffer +{ +public: + PolyDataBuffer(int bindingpoint, bool ssbo, bool needresize) : bindingpoint(bindingpoint) + { + } + + void BindRange(size_t start, size_t length) override; + void BindBase() override; + + int bindingpoint; +}; diff --git a/src/rendering/polyrenderer/backend/poly_framebuffer.cpp b/src/rendering/polyrenderer/backend/poly_framebuffer.cpp new file mode 100644 index 0000000000..0a261462d3 --- /dev/null +++ b/src/rendering/polyrenderer/backend/poly_framebuffer.cpp @@ -0,0 +1,558 @@ + +#include "v_video.h" +#include "m_png.h" +#include "templates.h" +#include "r_videoscale.h" +#include "actor.h" +#include "i_time.h" +#include "g_game.h" +#include "gamedata/fonts/v_text.h" + +#include "hwrenderer/utility/hw_clock.h" +#include "hwrenderer/utility/hw_vrmodes.h" +#include "hwrenderer/utility/hw_cvars.h" +#include "hwrenderer/models/hw_models.h" +#include "hwrenderer/scene/hw_skydome.h" +#include "hwrenderer/scene/hw_fakeflat.h" +#include "hwrenderer/scene/hw_drawinfo.h" +#include "hwrenderer/scene/hw_portal.h" +#include "hwrenderer/data/hw_viewpointbuffer.h" +#include "hwrenderer/data/flatvertices.h" +#include "hwrenderer/data/shaderuniforms.h" +#include "hwrenderer/dynlights/hw_lightbuffer.h" +#include "hwrenderer/postprocessing/hw_postprocess.h" + +#include "swrenderer/r_swscene.h" + +#include "poly_framebuffer.h" +#include "poly_buffers.h" +#include "poly_renderstate.h" +#include "poly_hwtexture.h" +#include "doomerrors.h" + +void Draw2D(F2DDrawer *drawer, FRenderState &state); +void DoWriteSavePic(FileWriter *file, ESSType ssformat, uint8_t *scr, int width, int height, sector_t *viewsector, bool upsidedown); + +EXTERN_CVAR(Bool, r_drawvoxels) +EXTERN_CVAR(Int, gl_tonemap) +EXTERN_CVAR(Int, screenblocks) +EXTERN_CVAR(Bool, cl_capfps) +EXTERN_CVAR(Bool, gl_no_skyclear) + +extern bool NoInterpolateView; +extern int rendered_commandbuffers; +extern int current_rendered_commandbuffers; + +extern bool gpuStatActive; +extern bool keepGpuStatActive; +extern FString gpuStatOutput; + +#ifdef WIN32 +void I_PresentPolyImage(int w, int h, const void *pixels); +#else +void I_PresentPolyImage(int w, int h, const void *pixels) { } +#endif + +PolyFrameBuffer::PolyFrameBuffer(void *hMonitor, bool fullscreen) : Super(hMonitor, fullscreen) +{ +} + +PolyFrameBuffer::~PolyFrameBuffer() +{ + // screen is already null at this point, but PolyHardwareTexture::ResetAll needs it during clean up. Is there a better way we can do this? + auto tmp = screen; + screen = this; + + PolyHardwareTexture::ResetAll(); + PolyBuffer::ResetAll(); + PPResource::ResetAll(); + + delete mVertexData; + delete mSkyData; + delete mViewpoints; + delete mLights; + mShadowMap.Reset(); + + screen = tmp; +} + +void PolyFrameBuffer::InitializeState() +{ + gl_vendorstring = "Poly"; + hwcaps = RFL_SHADER_STORAGE_BUFFER | RFL_BUFFER_STORAGE; + glslversion = 4.50f; + uniformblockalignment = 1; + maxuniformblock = 0x7fffffff; + + mVertexData = new FFlatVertexBuffer(GetWidth(), GetHeight()); + mSkyData = new FSkyVertexBuffer; + mViewpoints = new GLViewpointBuffer; + mLights = new FLightBuffer(); + + mRenderState.reset(new PolyRenderState()); + + CheckCanvas(); + + PolyTriangleDrawer::SetTransform(GetDrawCommands(), GetFrameMemory()->NewObject(Mat4f::Identity()), nullptr); +} + +void PolyFrameBuffer::CheckCanvas() +{ + if (!mCanvas || mCanvas->GetWidth() != GetWidth() || mCanvas->GetHeight() != GetHeight()) + { + DrawerThreads::WaitForWorkers(); + + mCanvas.reset(new DCanvas(0, 0, true)); + mCanvas->Resize(GetWidth(), GetHeight(), false); + + PolyTriangleDrawer::SetViewport(GetDrawCommands(), 0, 0, mCanvas->GetWidth(), mCanvas->GetHeight(), mCanvas.get()); + } +} + +const DrawerCommandQueuePtr &PolyFrameBuffer::GetDrawCommands() +{ + if (!mDrawCommands) + mDrawCommands = std::make_shared(&mFrameMemory); + return mDrawCommands; +} + +void PolyFrameBuffer::FlushDrawCommands() +{ + if (mDrawCommands) + { + DrawerThreads::Execute(mDrawCommands); + mDrawCommands.reset(); + } +} + +void PolyFrameBuffer::Update() +{ + twoD.Reset(); + Flush3D.Reset(); + + Flush3D.Clock(); + + Draw2D(); + Clear2D(); + + Flush3D.Unclock(); + + FlushDrawCommands(); + DrawerThreads::WaitForWorkers(); + mFrameMemory.Clear(); + + if (mCanvas && GetClientWidth() == mCanvas->GetWidth() && GetClientHeight() == mCanvas->GetHeight()) + { + I_PresentPolyImage(mCanvas->GetWidth(), mCanvas->GetHeight(), mCanvas->GetPixels()); + } + + CheckCanvas(); + PolyTriangleDrawer::SetTransform(GetDrawCommands(), GetFrameMemory()->NewObject(Mat4f::Identity()), nullptr); + + Super::Update(); +} + + +void PolyFrameBuffer::WriteSavePic(player_t *player, FileWriter *file, int width, int height) +{ + if (!V_IsHardwareRenderer()) + { + Super::WriteSavePic(player, file, width, height); + } + else + { + } +} + +sector_t *PolyFrameBuffer::RenderView(player_t *player) +{ + // To do: this is virtually identical to FGLRenderer::RenderView and should be merged. + + mRenderState->SetVertexBuffer(screen->mVertexData); + screen->mVertexData->Reset(); + + sector_t *retsec; + if (!V_IsHardwareRenderer()) + { + if (!swdrawer) swdrawer.reset(new SWSceneDrawer); + retsec = swdrawer->RenderView(player); + } + else + { + hw_ClearFakeFlat(); + + iter_dlightf = iter_dlight = draw_dlight = draw_dlightf = 0; + + checkBenchActive(); + + // reset statistics counters + ResetProfilingData(); + + // Get this before everything else + if (cl_capfps || r_NoInterpolate) r_viewpoint.TicFrac = 1.; + else r_viewpoint.TicFrac = I_GetTimeFrac(); + + screen->mLights->Clear(); + screen->mViewpoints->Clear(); + + // NoInterpolateView should have no bearing on camera textures, but needs to be preserved for the main view below. + bool saved_niv = NoInterpolateView; + NoInterpolateView = false; + + // Shader start time does not need to be handled per level. Just use the one from the camera to render from. + GetRenderState()->CheckTimer(player->camera->Level->ShaderStartTime); + // prepare all camera textures that have been used in the last frame. + // This must be done for all levels, not just the primary one! + for (auto Level : AllLevels()) + { + Level->canvasTextureInfo.UpdateAll([&](AActor *camera, FCanvasTexture *camtex, double fov) + { + RenderTextureView(camtex, camera, fov); + }); + } + NoInterpolateView = saved_niv; + + // now render the main view + float fovratio; + float ratio = r_viewwindow.WidescreenRatio; + if (r_viewwindow.WidescreenRatio >= 1.3f) + { + fovratio = 1.333333f; + } + else + { + fovratio = ratio; + } + + retsec = RenderViewpoint(r_viewpoint, player->camera, NULL, r_viewpoint.FieldOfView.Degrees, ratio, fovratio, true, true); + } + All.Unclock(); + return retsec; +} + +sector_t *PolyFrameBuffer::RenderViewpoint(FRenderViewpoint &mainvp, AActor * camera, IntRect * bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen) +{ + // To do: this is virtually identical to FGLRenderer::RenderViewpoint and should be merged. + + R_SetupFrame(mainvp, r_viewwindow, camera); + + if (mainview && toscreen) + UpdateShadowMap(); + + // Update the attenuation flag of all light defaults for each viewpoint. + // This function will only do something if the setting differs. + FLightDefaults::SetAttenuationForLevel(!!(camera->Level->flags3 & LEVEL3_ATTENUATE)); + + // Render (potentially) multiple views for stereo 3d + // Fixme. The view offsetting should be done with a static table and not require setup of the entire render state for the mode. + auto vrmode = VRMode::GetVRMode(mainview && toscreen); + for (int eye_ix = 0; eye_ix < vrmode->mEyeCount; ++eye_ix) + { + const auto &eye = vrmode->mEyes[eye_ix]; + screen->SetViewportRects(bounds); + + if (mainview) // Bind the scene frame buffer and turn on draw buffers used by ssao + { + //mRenderState->SetRenderTarget(GetBuffers()->SceneColor.View.get(), GetBuffers()->SceneDepthStencil.View.get(), GetBuffers()->GetWidth(), GetBuffers()->GetHeight(), Poly_FORMAT_R16G16B16A16_SFLOAT, GetBuffers()->GetSceneSamples()); + bool useSSAO = (gl_ssao != 0); + GetRenderState()->SetPassType(useSSAO ? GBUFFER_PASS : NORMAL_PASS); + GetRenderState()->EnableDrawBuffers(GetRenderState()->GetPassDrawBufferCount()); + } + + auto di = HWDrawInfo::StartDrawInfo(mainvp.ViewLevel, nullptr, mainvp, nullptr); + auto &vp = di->Viewpoint; + + di->Set3DViewport(*GetRenderState()); + di->SetViewArea(); + auto cm = di->SetFullbrightFlags(mainview ? vp.camera->player : nullptr); + di->Viewpoint.FieldOfView = fov; // Set the real FOV for the current scene (it's not necessarily the same as the global setting in r_viewpoint) + + // Stereo mode specific perspective projection + di->VPUniforms.mProjectionMatrix = eye.GetProjection(fov, ratio, fovratio); + // Stereo mode specific viewpoint adjustment + vp.Pos += eye.GetViewShift(vp.HWAngles.Yaw.Degrees); + di->SetupView(*GetRenderState(), vp.Pos.X, vp.Pos.Y, vp.Pos.Z, false, false); + + // std::function until this can be done better in a cross-API fashion. + di->ProcessScene(toscreen, [&](HWDrawInfo *di, int mode) { + DrawScene(di, mode); + }); + + if (mainview) + { + PostProcess.Clock(); + if (toscreen) di->EndDrawScene(mainvp.sector, *GetRenderState()); // do not call this for camera textures. + + if (GetRenderState()->GetPassType() == GBUFFER_PASS) // Turn off ssao draw buffers + { + GetRenderState()->SetPassType(NORMAL_PASS); + GetRenderState()->EnableDrawBuffers(1); + } + + //mPostprocess->BlitSceneToPostprocess(); // Copy the resulting scene to the current post process texture + + PostProcessScene(cm, [&]() { di->DrawEndScene2D(mainvp.sector, *GetRenderState()); }); + + PostProcess.Unclock(); + } + di->EndDrawInfo(); + +#if 0 + if (vrmode->mEyeCount > 1) + mBuffers->BlitToEyeTexture(eye_ix); +#endif + } + + return mainvp.sector; +} + +void PolyFrameBuffer::RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, double FOV) +{ +#if 0 + // This doesn't need to clear the fake flat cache. It can be shared between camera textures and the main view of a scene. + FMaterial *mat = FMaterial::ValidateTexture(tex, false); + auto BaseLayer = static_cast(mat->GetLayer(0, 0)); + + int width = mat->TextureWidth(); + int height = mat->TextureHeight(); + PolyTextureImage *image = BaseLayer->GetImage(tex, 0, 0); + PolyTextureImage *depthStencil = BaseLayer->GetDepthStencil(tex); + + mRenderState->EndRenderPass(); + + PolyImageTransition barrier0; + barrier0.addImage(image, Poly_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true); + barrier0.execute(GetDrawCommands()); + + mRenderState->SetRenderTarget(image->View.get(), depthStencil->View.get(), image->Image->width, image->Image->height, Poly_FORMAT_R8G8B8A8_UNORM, Poly_SAMPLE_COUNT_1_BIT); + + IntRect bounds; + bounds.left = bounds.top = 0; + bounds.width = MIN(mat->GetWidth(), image->Image->width); + bounds.height = MIN(mat->GetHeight(), image->Image->height); + + FRenderViewpoint texvp; + RenderViewpoint(texvp, Viewpoint, &bounds, FOV, (float)width / height, (float)width / height, false, false); + + mRenderState->EndRenderPass(); + + PolyImageTransition barrier1; + barrier1.addImage(image, Poly_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false); + barrier1.execute(GetDrawCommands()); + + mRenderState->SetRenderTarget(GetBuffers()->SceneColor.View.get(), GetBuffers()->SceneDepthStencil.View.get(), GetBuffers()->GetWidth(), GetBuffers()->GetHeight(), Poly_FORMAT_R16G16B16A16_SFLOAT, GetBuffers()->GetSceneSamples()); + + tex->SetUpdated(true); +#endif +} + +void PolyFrameBuffer::DrawScene(HWDrawInfo *di, int drawmode) +{ + // To do: this is virtually identical to FGLRenderer::DrawScene and should be merged. + + static int recursion = 0; + static int ssao_portals_available = 0; + const auto &vp = di->Viewpoint; + + bool applySSAO = false; + if (drawmode == DM_MAINVIEW) + { + ssao_portals_available = gl_ssao_portals; + applySSAO = true; + } + else if (drawmode == DM_OFFSCREEN) + { + ssao_portals_available = 0; + } + else if (drawmode == DM_PORTAL && ssao_portals_available > 0) + { + applySSAO = true; + ssao_portals_available--; + } + + if (vp.camera != nullptr) + { + ActorRenderFlags savedflags = vp.camera->renderflags; + di->CreateScene(drawmode == DM_MAINVIEW); + vp.camera->renderflags = savedflags; + } + else + { + di->CreateScene(false); + } + + GetRenderState()->SetDepthMask(true); + if (!gl_no_skyclear) screen->mPortalState->RenderFirstSkyPortal(recursion, di, *GetRenderState()); + + di->RenderScene(*GetRenderState()); + + if (applySSAO && GetRenderState()->GetPassType() == GBUFFER_PASS) + { + //mPostprocess->AmbientOccludeScene(di->VPUniforms.mProjectionMatrix.get()[5]); + //screen->mViewpoints->Bind(*GetRenderState(), di->vpIndex); + } + + // Handle all portals after rendering the opaque objects but before + // doing all translucent stuff + recursion++; + screen->mPortalState->EndFrame(di, *GetRenderState()); + recursion--; + di->RenderTranslucent(*GetRenderState()); +} + +void PolyFrameBuffer::PostProcessScene(int fixedcm, const std::function &afterBloomDrawEndScene2D) +{ + afterBloomDrawEndScene2D(); +} + +uint32_t PolyFrameBuffer::GetCaps() +{ + if (!V_IsHardwareRenderer()) + return Super::GetCaps(); + + // describe our basic feature set + ActorRenderFeatureFlags FlagSet = RFF_FLATSPRITES | RFF_MODELS | RFF_SLOPE3DFLOORS | + RFF_TILTPITCH | RFF_ROLLSPRITES | RFF_POLYGONAL | RFF_MATSHADER | RFF_POSTSHADER | RFF_BRIGHTMAP; + if (r_drawvoxels) + FlagSet |= RFF_VOXELS; + + if (gl_tonemap != 5) // not running palette tonemap shader + FlagSet |= RFF_TRUECOLOR; + + return (uint32_t)FlagSet; +} + +void PolyFrameBuffer::SetVSync(bool vsync) +{ + // This is handled in PolySwapChain::AcquireImage. +} + +void PolyFrameBuffer::CleanForRestart() +{ + // force recreation of the SW scene drawer to ensure it gets a new set of resources. + swdrawer.reset(); +} + +void PolyFrameBuffer::PrecacheMaterial(FMaterial *mat, int translation) +{ + auto tex = mat->tex; + if (tex->isSWCanvas()) return; + + // Textures that are already scaled in the texture lump will not get replaced by hires textures. + int flags = mat->isExpanded() ? CTF_Expand : (gl_texture_usehires && !tex->isScaled()) ? CTF_CheckHires : 0; + auto base = static_cast(mat->GetLayer(0, translation)); + + base->Precache(mat, translation, flags); +} + +IHardwareTexture *PolyFrameBuffer::CreateHardwareTexture() +{ + return new PolyHardwareTexture(); +} + +FModelRenderer *PolyFrameBuffer::CreateModelRenderer(int mli) +{ + return new FHWModelRenderer(nullptr, *GetRenderState(), mli); +} + +IVertexBuffer *PolyFrameBuffer::CreateVertexBuffer() +{ + return new PolyVertexBuffer(); +} + +IIndexBuffer *PolyFrameBuffer::CreateIndexBuffer() +{ + return new PolyIndexBuffer(); +} + +IDataBuffer *PolyFrameBuffer::CreateDataBuffer(int bindingpoint, bool ssbo, bool needsresize) +{ + return new PolyDataBuffer(bindingpoint, ssbo, needsresize); +} + +void PolyFrameBuffer::SetTextureFilterMode() +{ + TextureFilterChanged(); +} + +void PolyFrameBuffer::TextureFilterChanged() +{ +} + +void PolyFrameBuffer::StartPrecaching() +{ +} + +void PolyFrameBuffer::BlurScene(float amount) +{ +} + +void PolyFrameBuffer::UpdatePalette() +{ +} + +FTexture *PolyFrameBuffer::WipeStartScreen() +{ + const auto &viewport = screen->mScreenViewport; + auto tex = new FWrapperTexture(viewport.width, viewport.height, 1); + auto systex = static_cast(tex->GetSystemTexture()); + + systex->CreateWipeTexture(viewport.width, viewport.height, "WipeStartScreen"); + + return tex; +} + +FTexture *PolyFrameBuffer::WipeEndScreen() +{ + Draw2D(); + Clear2D(); + + const auto &viewport = screen->mScreenViewport; + auto tex = new FWrapperTexture(viewport.width, viewport.height, 1); + auto systex = static_cast(tex->GetSystemTexture()); + + systex->CreateWipeTexture(viewport.width, viewport.height, "WipeEndScreen"); + + return tex; +} + +TArray PolyFrameBuffer::GetScreenshotBuffer(int &pitch, ESSType &color_type, float &gamma) +{ + int w = SCREENWIDTH; + int h = SCREENHEIGHT; + + IntRect box; + box.left = 0; + box.top = 0; + box.width = w; + box.height = h; + //mPostprocess->DrawPresentTexture(box, true, true); + + TArray ScreenshotBuffer(w * h * 3, true); + //CopyScreenToBuffer(w, h, ScreenshotBuffer.Data()); + + pitch = w * 3; + color_type = SS_RGB; + gamma = 1.0f; + return ScreenshotBuffer; +} + +void PolyFrameBuffer::BeginFrame() +{ + SetViewportRects(nullptr); + CheckCanvas(); +} + +void PolyFrameBuffer::Draw2D() +{ + ::Draw2D(&m2DDrawer, *mRenderState); +} + +unsigned int PolyFrameBuffer::GetLightBufferBlockSize() const +{ + return mLights->GetBlockSize(); +} + +void PolyFrameBuffer::UpdateShadowMap() +{ +} diff --git a/src/rendering/polyrenderer/backend/poly_framebuffer.h b/src/rendering/polyrenderer/backend/poly_framebuffer.h new file mode 100644 index 0000000000..3e05d01a26 --- /dev/null +++ b/src/rendering/polyrenderer/backend/poly_framebuffer.h @@ -0,0 +1,75 @@ +#pragma once + +#include "gl_sysfb.h" +#include "rendering/swrenderer/r_memory.h" +#include "rendering/swrenderer/drawers/r_thread.h" +#include "rendering/polyrenderer/drawers/poly_triangle.h" + +struct FRenderViewpoint; +class PolyDataBuffer; +class PolyRenderState; +class SWSceneDrawer; + +class PolyFrameBuffer : public SystemBaseFrameBuffer +{ + typedef SystemBaseFrameBuffer Super; + +public: + RenderMemory *GetFrameMemory() { return &mFrameMemory; } + PolyRenderState *GetRenderState() { return mRenderState.get(); } + const DrawerCommandQueuePtr &GetDrawCommands(); + void FlushDrawCommands(); + + unsigned int GetLightBufferBlockSize() const; + + std::unique_ptr swdrawer; + + PolyFrameBuffer(void *hMonitor, bool fullscreen); + ~PolyFrameBuffer(); + + void Update(); + + void InitializeState() override; + + void CleanForRestart() override; + void PrecacheMaterial(FMaterial *mat, int translation) override; + void UpdatePalette() override; + uint32_t GetCaps() override; + void WriteSavePic(player_t *player, FileWriter *file, int width, int height) override; + sector_t *RenderView(player_t *player) override; + void SetTextureFilterMode() override; + void TextureFilterChanged() override; + void StartPrecaching() override; + void BeginFrame() override; + void BlurScene(float amount) override; + void PostProcessScene(int fixedcm, const std::function &afterBloomDrawEndScene2D) override; + + IHardwareTexture *CreateHardwareTexture() override; + FModelRenderer *CreateModelRenderer(int mli) override; + IVertexBuffer *CreateVertexBuffer() override; + IIndexBuffer *CreateIndexBuffer() override; + IDataBuffer *CreateDataBuffer(int bindingpoint, bool ssbo, bool needsresize) override; + + FTexture *WipeStartScreen() override; + FTexture *WipeEndScreen() override; + + TArray GetScreenshotBuffer(int &pitch, ESSType &color_type, float &gamma) override; + + void SetVSync(bool vsync) override; + void Draw2D() override; + +private: + sector_t *RenderViewpoint(FRenderViewpoint &mainvp, AActor * camera, IntRect * bounds, float fov, float ratio, float fovratio, bool mainview, bool toscreen); + void RenderTextureView(FCanvasTexture *tex, AActor *Viewpoint, double FOV); + void DrawScene(HWDrawInfo *di, int drawmode); + void UpdateShadowMap(); + + void CheckCanvas(); + + std::unique_ptr mRenderState; + std::unique_ptr mCanvas; + std::shared_ptr mDrawCommands; + RenderMemory mFrameMemory; +}; + +inline PolyFrameBuffer *GetPolyFrameBuffer() { return static_cast(screen); } diff --git a/src/rendering/polyrenderer/backend/poly_hwtexture.cpp b/src/rendering/polyrenderer/backend/poly_hwtexture.cpp new file mode 100644 index 0000000000..9302738be0 --- /dev/null +++ b/src/rendering/polyrenderer/backend/poly_hwtexture.cpp @@ -0,0 +1,131 @@ + +#include "templates.h" +#include "c_cvars.h" +#include "r_data/colormaps.h" +#include "hwrenderer/textures/hw_material.h" +#include "hwrenderer/utility/hw_cvars.h" +#include "hwrenderer/scene/hw_renderstate.h" +#include "poly_framebuffer.h" +#include "poly_hwtexture.h" + +PolyHardwareTexture *PolyHardwareTexture::First = nullptr; + +PolyHardwareTexture::PolyHardwareTexture() +{ + Next = First; + First = this; + if (Next) Next->Prev = this; +} + +PolyHardwareTexture::~PolyHardwareTexture() +{ + if (Next) Next->Prev = Prev; + if (Prev) Prev->Next = Next; + else First = Next; + + Reset(); +} + +void PolyHardwareTexture::ResetAll() +{ + for (PolyHardwareTexture *cur = PolyHardwareTexture::First; cur; cur = cur->Next) + cur->Reset(); +} + +void PolyHardwareTexture::Reset() +{ +} + +void PolyHardwareTexture::Precache(FMaterial *mat, int translation, int flags) +{ +#if 0 + int numLayers = mat->GetLayers(); + GetImage(mat->tex, translation, flags); + for (int i = 1; i < numLayers; i++) + { + FTexture *layer; + auto systex = static_cast(mat->GetLayer(i, 0, &layer)); + systex->GetImage(layer, 0, mat->isExpanded() ? CTF_Expand : 0); + } +#endif +} + +DCanvas *PolyHardwareTexture::GetImage(const FMaterialState &state) +{ + if (!mCanvas) + { + FMaterial *mat = state.mMaterial; + FTexture *tex = state.mMaterial->tex; + int clampmode = state.mClampMode; + int translation = state.mTranslation; + + if (tex->UseType == ETextureType::SWCanvas) clampmode = CLAMP_NOFILTER; + if (tex->isHardwareCanvas()) clampmode = CLAMP_CAMTEX; + else if ((tex->isWarped() || tex->shaderindex >= FIRST_USER_SHADER) && clampmode <= CLAMP_XY) clampmode = CLAMP_NONE; + + // Textures that are already scaled in the texture lump will not get replaced by hires textures. + int flags = state.mMaterial->isExpanded() ? CTF_Expand : (gl_texture_usehires && !tex->isScaled() && clampmode <= CLAMP_XY) ? CTF_CheckHires : 0; + + if (tex->isHardwareCanvas()) static_cast(tex)->NeedUpdate(); + + CreateImage(tex, translation, flags); + } + + return mCanvas.get(); +} + +void PolyHardwareTexture::AllocateBuffer(int w, int h, int texelsize) +{ + if (!mCanvas || mCanvas->GetWidth() != w || mCanvas->GetHeight() != h) + { + mCanvas.reset(new DCanvas(0, 0, texelsize == 4)); + mCanvas->Resize(w, h, false); + } +} + +uint8_t *PolyHardwareTexture::MapBuffer() +{ + return mCanvas->GetPixels(); +} + +unsigned int PolyHardwareTexture::CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, const char *name) +{ + return 0; +} + +void PolyHardwareTexture::CreateWipeTexture(int w, int h, const char *name) +{ + if (!mCanvas || mCanvas->GetWidth() != w || mCanvas->GetHeight() != h) + { + mCanvas.reset(new DCanvas(0, 0, true)); + mCanvas->Resize(w, h, false); + } +} + +void PolyHardwareTexture::CreateImage(FTexture *tex, int translation, int flags) +{ + mCanvas.reset(new DCanvas(0, 0, true)); + + if (!tex->isHardwareCanvas()) + { + if (translation <= 0) + { + translation = -translation; + } + else + { + auto remap = TranslationToTable(translation); + translation = remap == nullptr ? 0 : remap->GetUniqueIndex(); + } + + FTextureBuffer texbuffer = tex->CreateTexBuffer(translation, flags | CTF_ProcessData); + mCanvas->Resize(texbuffer.mWidth, texbuffer.mHeight, false); + memcpy(mCanvas->GetPixels(), texbuffer.mBuffer, texbuffer.mWidth * texbuffer.mHeight * 4); + } + else + { + int w = tex->GetWidth(); + int h = tex->GetHeight(); + mCanvas->Resize(w, h, false); + } +} diff --git a/src/rendering/polyrenderer/backend/poly_hwtexture.h b/src/rendering/polyrenderer/backend/poly_hwtexture.h new file mode 100644 index 0000000000..84d1147bf7 --- /dev/null +++ b/src/rendering/polyrenderer/backend/poly_hwtexture.h @@ -0,0 +1,45 @@ +#pragma once + +#ifdef LoadImage +#undef LoadImage +#endif + +#define SHADED_TEXTURE -1 +#define DIRECT_PALETTE -2 + +#include "tarray.h" +#include "hwrenderer/textures/hw_ihwtexture.h" +#include "volk/volk.h" + +struct FMaterialState; +class PolyBuffer; + +class PolyHardwareTexture : public IHardwareTexture +{ +public: + PolyHardwareTexture(); + ~PolyHardwareTexture(); + + static void ResetAll(); + void Reset(); + + void Precache(FMaterial *mat, int translation, int flags); + + DCanvas *GetImage(const FMaterialState &state); + + // Software renderer stuff + void AllocateBuffer(int w, int h, int texelsize) override; + uint8_t *MapBuffer() override; + unsigned int CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, int translation, const char *name) override; + + // Wipe screen + void CreateWipeTexture(int w, int h, const char *name); + +private: + void CreateImage(FTexture *tex, int translation, int flags); + + static PolyHardwareTexture *First; + PolyHardwareTexture *Prev = nullptr; + PolyHardwareTexture *Next = nullptr; + std::unique_ptr mCanvas; +}; diff --git a/src/rendering/polyrenderer/backend/poly_renderstate.cpp b/src/rendering/polyrenderer/backend/poly_renderstate.cpp new file mode 100644 index 0000000000..527f3e4330 --- /dev/null +++ b/src/rendering/polyrenderer/backend/poly_renderstate.cpp @@ -0,0 +1,178 @@ + +#include "polyrenderer/backend/poly_renderstate.h" +#include "polyrenderer/backend/poly_framebuffer.h" +#include "polyrenderer/backend/poly_hwtexture.h" +#include "templates.h" +#include "doomstat.h" +#include "r_data/colormaps.h" +#include "hwrenderer/scene/hw_skydome.h" +#include "hwrenderer/scene/hw_viewpointuniforms.h" +#include "hwrenderer/dynlights/hw_lightbuffer.h" +#include "hwrenderer/utility/hw_cvars.h" +#include "hwrenderer/utility/hw_clock.h" +#include "hwrenderer/data/flatvertices.h" +#include "hwrenderer/data/hw_viewpointbuffer.h" +#include "hwrenderer/data/shaderuniforms.h" + +static PolyDrawMode dtToDrawMode[] = +{ + PolyDrawMode::Triangles, // DT_Points + PolyDrawMode::Triangles, // DT_Lines + PolyDrawMode::Triangles, // DT_Triangles + PolyDrawMode::TriangleFan, // DT_TriangleFan + PolyDrawMode::TriangleStrip, // DT_TriangleStrip +}; + +PolyRenderState::PolyRenderState() +{ + Reset(); +} + +void PolyRenderState::ClearScreen() +{ + screen->mViewpoints->Set2D(*this, SCREENWIDTH, SCREENHEIGHT); + SetColor(0, 0, 0); + Draw(DT_TriangleStrip, FFlatVertexBuffer::FULLSCREEN_INDEX, 4, true); +} + +void PolyRenderState::Draw(int dt, int index, int count, bool apply) +{ + if (apply) + Apply(); + + auto fb = GetPolyFrameBuffer(); + TriVertex *vertices = fb->GetFrameMemory()->AllocMemory(count); + static_cast(mVertexBuffer)->CopyVertices(vertices, count, index); + PolyTriangleDrawer::DrawArray(fb->GetDrawCommands(), args, vertices, count, dtToDrawMode[dt]); +} + +void PolyRenderState::DrawIndexed(int dt, int index, int count, bool apply) +{ + if (apply) + Apply(); + + auto fb = GetPolyFrameBuffer(); + TriVertex *vertices = fb->GetFrameMemory()->AllocMemory(count); + static_cast(mVertexBuffer)->CopyIndexed(vertices, (uint32_t *)mIndexBuffer->Memory(), count, index); + PolyTriangleDrawer::DrawArray(fb->GetDrawCommands(), args, vertices, count, dtToDrawMode[dt]); +} + +bool PolyRenderState::SetDepthClamp(bool on) +{ + bool lastValue = mDepthClamp; + mDepthClamp = on; + return lastValue; +} + +void PolyRenderState::SetDepthMask(bool on) +{ +} + +void PolyRenderState::SetDepthFunc(int func) +{ +} + +void PolyRenderState::SetDepthRange(float min, float max) +{ +} + +void PolyRenderState::SetColorMask(bool r, bool g, bool b, bool a) +{ +} + +void PolyRenderState::SetStencil(int offs, int op, int flags) +{ +} + +void PolyRenderState::SetCulling(int mode) +{ +} + +void PolyRenderState::EnableClipDistance(int num, bool state) +{ +} + +void PolyRenderState::Clear(int targets) +{ +} + +void PolyRenderState::EnableStencil(bool on) +{ +} + +void PolyRenderState::SetScissor(int x, int y, int w, int h) +{ +} + +void PolyRenderState::SetViewport(int x, int y, int w, int h) +{ +} + +void PolyRenderState::EnableDepthTest(bool on) +{ +} + +void PolyRenderState::EnableMultisampling(bool on) +{ +} + +void PolyRenderState::EnableLineSmooth(bool on) +{ +} + +void PolyRenderState::EnableDrawBuffers(int count) +{ +} + +void PolyRenderState::Apply() +{ + drawcalls.Clock(); + + args.SetStencilTest(false); + args.SetDepthTest(false); + args.SetWriteStencil(false); + args.SetWriteDepth(false); + args.SetNoColormap(); + + args.SetColor(MAKEARGB( + static_cast(mStreamData.uVertexColor.W * 255.0f + 0.5f), + static_cast(mStreamData.uVertexColor.X * 255.0f + 0.5f), + static_cast(mStreamData.uVertexColor.Y * 255.0f + 0.5f), + static_cast(mStreamData.uVertexColor.Z * 255.0f + 0.5f)), 0); + + if (mMaterial.mChanged && mMaterial.mMaterial) + { + auto base = static_cast(mMaterial.mMaterial->GetLayer(0, mMaterial.mTranslation)); + if (base) + { + DCanvas *texcanvas = base->GetImage(mMaterial); + args.SetTexture(texcanvas->GetPixels(), texcanvas->GetHeight(), texcanvas->GetWidth()); + args.SetStyle(TriBlendMode::Opaque); + } + else + { + args.SetStyle(TriBlendMode::Fill); + } + + mMaterial.mChanged = false; + } + + auto fb = GetPolyFrameBuffer(); + PolyTriangleDrawer::SetTwoSided(fb->GetDrawCommands(), true); + + drawcalls.Unclock(); +} + +void PolyRenderState::Bind(PolyDataBuffer *buffer, uint32_t offset, uint32_t length) +{ + if (buffer->bindingpoint == VIEWPOINT_BINDINGPOINT) + { + HWViewpointUniforms *uniforms = reinterpret_cast(static_cast(buffer->Memory()) + offset); + + Mat4f viewToProj = Mat4f::FromValues(uniforms->mProjectionMatrix.get()); + Mat4f worldToView = Mat4f::FromValues(uniforms->mViewMatrix.get()); + + auto fb = GetPolyFrameBuffer(); + PolyTriangleDrawer::SetTransform(fb->GetDrawCommands(), fb->GetFrameMemory()->NewObject(viewToProj * worldToView), nullptr); + } +} diff --git a/src/rendering/polyrenderer/backend/poly_renderstate.h b/src/rendering/polyrenderer/backend/poly_renderstate.h new file mode 100644 index 0000000000..84c9c190a1 --- /dev/null +++ b/src/rendering/polyrenderer/backend/poly_renderstate.h @@ -0,0 +1,50 @@ + +#pragma once + +#include "polyrenderer/backend/poly_buffers.h" +#include "rendering/polyrenderer/drawers/poly_triangle.h" + +#include "name.h" + +#include "hwrenderer/scene/hw_drawstructs.h" +#include "hwrenderer/scene/hw_renderstate.h" +#include "hwrenderer/textures/hw_material.h" + +class PolyRenderPassSetup; + +class PolyRenderState : public FRenderState +{ +public: + PolyRenderState(); + + // Draw commands + void ClearScreen() override; + void Draw(int dt, int index, int count, bool apply = true) override; + void DrawIndexed(int dt, int index, int count, bool apply = true) override; + + // Immediate render state change commands. These only change infrequently and should not clutter the render state. + bool SetDepthClamp(bool on) override; + void SetDepthMask(bool on) override; + void SetDepthFunc(int func) override; + void SetDepthRange(float min, float max) override; + void SetColorMask(bool r, bool g, bool b, bool a) override; + void SetStencil(int offs, int op, int flags = -1) override; + void SetCulling(int mode) override; + void EnableClipDistance(int num, bool state) override; + void Clear(int targets) override; + void EnableStencil(bool on) override; + void SetScissor(int x, int y, int w, int h) override; + void SetViewport(int x, int y, int w, int h) override; + void EnableDepthTest(bool on) override; + void EnableMultisampling(bool on) override; + void EnableLineSmooth(bool on) override; + void EnableDrawBuffers(int count) override; + + void Bind(PolyDataBuffer *buffer, uint32_t offset, uint32_t length); + +private: + void Apply(); + + bool mDepthClamp = true; + PolyDrawArgs args; +}; diff --git a/src/rendering/polyrenderer/drawers/poly_draw_args.h b/src/rendering/polyrenderer/drawers/poly_draw_args.h index b40e209a29..0c6a6791a0 100644 --- a/src/rendering/polyrenderer/drawers/poly_draw_args.h +++ b/src/rendering/polyrenderer/drawers/poly_draw_args.h @@ -70,7 +70,9 @@ public: void SetTexture(FSoftwareTexture *texture, FRenderStyle style); void SetTexture(FSoftwareTexture *texture, uint32_t translationID, FRenderStyle style); void SetLight(FSWColormap *basecolormap, uint32_t lightlevel, double globVis, bool fixed); + void SetNoColormap() { mLight = 255; mFixedLight = true; mLightRed = 256; mLightGreen = 256; mLightBlue = 256; mLightAlpha = 256; mFadeRed = 0; mFadeGreen = 0; mFadeBlue = 0; mFadeAlpha = 0; mDesaturate = 0; mSimpleShade = true; mColormaps = nullptr; } void SetDepthTest(bool enable) { mDepthTest = enable; } + void SetStencilTest(bool enable) { mStencilTest = enable; } void SetStencilTestValue(uint8_t stencilTestValue) { mStencilTestValue = stencilTestValue; } void SetWriteColor(bool enable) { mWriteColor = enable; } void SetWriteStencil(bool enable, uint8_t stencilWriteValue = 0) { mWriteStencil = enable; mStencilWriteValue = stencilWriteValue; } @@ -92,6 +94,7 @@ public: const uint8_t *Translation() const { return mTranslation; } bool WriteStencil() const { return mWriteStencil; } + bool StencilTest() const { return mStencilTest; } uint8_t StencilTestValue() const { return mStencilTestValue; } uint8_t StencilWriteValue() const { return mStencilWriteValue; } @@ -128,6 +131,7 @@ public: private: bool mDepthTest = false; + bool mStencilTest = true; bool mWriteStencil = true; bool mWriteColor = true; bool mWriteDepth = true; diff --git a/src/rendering/polyrenderer/drawers/poly_triangle.h b/src/rendering/polyrenderer/drawers/poly_triangle.h index 1ba182a70f..50c0f6ad49 100644 --- a/src/rendering/polyrenderer/drawers/poly_triangle.h +++ b/src/rendering/polyrenderer/drawers/poly_triangle.h @@ -29,6 +29,7 @@ #include "polyrenderer/drawers/poly_buffer.h" #include "polyrenderer/drawers/poly_draw_args.h" +class DCanvas; class PolyDrawerCommand; class PolyTriangleDrawer diff --git a/src/rendering/polyrenderer/drawers/screen_triangle.cpp b/src/rendering/polyrenderer/drawers/screen_triangle.cpp index c989a94d14..dc6a66c3c9 100644 --- a/src/rendering/polyrenderer/drawers/screen_triangle.cpp +++ b/src/rendering/polyrenderer/drawers/screen_triangle.cpp @@ -143,7 +143,7 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, PolyTriangleThreadDat int opt = 0; if (args->uniforms->DepthTest()) opt |= SWTRI_DepthTest; - /*if (args->uniforms->StencilTest())*/ opt |= SWTRI_StencilTest; + if (args->uniforms->StencilTest()) opt |= SWTRI_StencilTest; if (args->uniforms->WriteColor()) opt |= SWTRI_WriteColor; if (args->uniforms->WriteDepth()) opt |= SWTRI_WriteDepth; if (args->uniforms->WriteStencil()) opt |= SWTRI_WriteStencil; diff --git a/src/rendering/polyrenderer/drawers/screen_triangle.h b/src/rendering/polyrenderer/drawers/screen_triangle.h index e99260a3f1..66ae24f653 100644 --- a/src/rendering/polyrenderer/drawers/screen_triangle.h +++ b/src/rendering/polyrenderer/drawers/screen_triangle.h @@ -24,6 +24,7 @@ #include #include +#include "r_data/renderstyle.h" class FString; class PolyDrawArgs; diff --git a/src/rendering/polyrenderer/math/gpu_types.cpp b/src/rendering/polyrenderer/math/gpu_types.cpp index 3e3d8182ab..7ec8dc3313 100644 --- a/src/rendering/polyrenderer/math/gpu_types.cpp +++ b/src/rendering/polyrenderer/math/gpu_types.cpp @@ -42,7 +42,7 @@ Mat4f Mat4f::Identity() return m; } -Mat4f Mat4f::FromValues(float *matrix) +Mat4f Mat4f::FromValues(const float *matrix) { Mat4f m; memcpy(m.Matrix, matrix, sizeof(m.Matrix)); diff --git a/src/rendering/polyrenderer/math/gpu_types.h b/src/rendering/polyrenderer/math/gpu_types.h index 0a0c261ddb..6892be46e7 100644 --- a/src/rendering/polyrenderer/math/gpu_types.h +++ b/src/rendering/polyrenderer/math/gpu_types.h @@ -115,7 +115,7 @@ class Mat4f public: static Mat4f Null(); static Mat4f Identity(); - static Mat4f FromValues(float *matrix); + static Mat4f FromValues(const float *matrix); static Mat4f Transpose(const Mat4f &matrix); static Mat4f Translate(float x, float y, float z); static Mat4f Scale(float x, float y, float z); diff --git a/src/v_video.cpp b/src/v_video.cpp index 9df3714779..e198d9efd6 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -210,7 +210,7 @@ DCanvas::~DCanvas () // //========================================================================== -void DCanvas::Resize(int width, int height) +void DCanvas::Resize(int width, int height, bool optimizepitch) { Width = width; Height = height; @@ -221,7 +221,7 @@ void DCanvas::Resize(int width, int height) // longer than the width. The values used here are all based on // empirical evidence. - if (width <= 640) + if (width <= 640 || !optimizepitch) { // For low resolutions, just keep the pitch the same as the width. // Some speedup can be seen using the technique below, but the speedup diff --git a/src/v_video.h b/src/v_video.h index 4c0597c4f4..af6283a5c4 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -326,7 +326,7 @@ class DCanvas public: DCanvas (int width, int height, bool bgra); ~DCanvas (); - void Resize(int width, int height); + void Resize(int width, int height, bool optimizepitch = true); // Member variable access inline uint8_t *GetPixels () const { return Pixels.Data(); } diff --git a/src/win32/hardware.cpp b/src/win32/hardware.cpp index 7f101112c8..467550a36f 100644 --- a/src/win32/hardware.cpp +++ b/src/win32/hardware.cpp @@ -44,6 +44,7 @@ #include "m_argv.h" #include "version.h" #include "win32glvideo.h" +#include "win32polyvideo.h" #ifdef HAVE_VULKAN #include "win32vulkanvideo.h" #endif @@ -129,8 +130,12 @@ void I_InitGraphics () // are the active app. Huh? } + if (vid_enablevulkan == 2) + { + Video = new Win32PolyVideo(); + } #ifdef HAVE_VULKAN - if (vid_enablevulkan == 1) + else if (vid_enablevulkan == 1) { // first try Vulkan, if that fails OpenGL try @@ -143,8 +148,8 @@ void I_InitGraphics () Video = new Win32GLVideo(); } } - else #endif + else { Video = new Win32GLVideo(); } diff --git a/src/win32/win32polyvideo.cpp b/src/win32/win32polyvideo.cpp new file mode 100644 index 0000000000..faf6c937a5 --- /dev/null +++ b/src/win32/win32polyvideo.cpp @@ -0,0 +1,23 @@ + +#include +#include "hardware.h" +#include + +extern HWND Window; + +void I_PresentPolyImage(int w, int h, const void *pixels) +{ + BITMAPV5HEADER info = {}; + info.bV5Size = sizeof(BITMAPV5HEADER); + info.bV5Width = w; + info.bV5Height = -h; + info.bV5Planes = 1; + info.bV5BitCount = 32; + info.bV5Compression = BI_RGB; + info.bV5SizeImage = 0; + info.bV5CSType = LCS_WINDOWS_COLOR_SPACE; + + HDC dc = GetDC(Window); + SetDIBitsToDevice(dc, 0, 0, w, h, 0, 0, 0, h, pixels, (const BITMAPINFO *)&info, DIB_RGB_COLORS); + ReleaseDC(Window, dc); +} diff --git a/src/win32/win32polyvideo.h b/src/win32/win32polyvideo.h new file mode 100644 index 0000000000..e1ad6d503b --- /dev/null +++ b/src/win32/win32polyvideo.h @@ -0,0 +1,21 @@ +#pragma once + +#include "win32basevideo.h" +#include "c_cvars.h" +#include "rendering/polyrenderer/backend/poly_framebuffer.h" + +EXTERN_CVAR(Bool, fullscreen) + +class Win32PolyVideo : public Win32BaseVideo +{ +public: + void Shutdown() override + { + } + + DFrameBuffer *CreateFrameBuffer() override + { + auto fb = new PolyFrameBuffer(m_hMonitor, fullscreen); + return fb; + } +};