mirror of
https://github.com/ZDoom/Raze.git
synced 2025-05-29 16:31:43 +00:00
- added the softpoly and Vulkan backend code fron GZDoom.
Not hooked up yet.
This commit is contained in:
parent
2841154683
commit
611dad7f69
195 changed files with 135802 additions and 38 deletions
162
source/common/rendering/polyrenderer/backend/poly_buffers.cpp
Normal file
162
source/common/rendering/polyrenderer/backend/poly_buffers.cpp
Normal file
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
** Softpoly backend
|
||||
** Copyright (c) 2016-2020 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include "poly_buffers.h"
|
||||
#include "poly_framebuffer.h"
|
||||
#include "poly_renderstate.h"
|
||||
#include "poly_thread.h"
|
||||
#include "engineerrors.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;
|
||||
|
||||
auto fb = GetPolyFrameBuffer();
|
||||
if (fb && !mData.empty())
|
||||
fb->FrameDeleteList.Buffers.push_back(std::move(mData));
|
||||
}
|
||||
|
||||
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<uint8_t*>(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)
|
||||
{
|
||||
if (mData.size() < (size_t)size)
|
||||
Resize(size);
|
||||
return map;
|
||||
}
|
||||
|
||||
void PolyBuffer::Unlock()
|
||||
{
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PolyVertexBuffer::SetFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs)
|
||||
{
|
||||
VertexFormat = GetPolyFrameBuffer()->GetRenderState()->GetVertexFormat(numBindingPoints, numAttributes, stride, attrs);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PolyVertexInputAssembly::Load(PolyTriangleThreadData *thread, const void *vertices, int index)
|
||||
{
|
||||
const uint8_t *vertex = static_cast<const uint8_t*>(vertices) + mStride * index;
|
||||
const float *attrVertex = reinterpret_cast<const float*>(vertex + mOffsets[VATTR_VERTEX]);
|
||||
const float *attrTexcoord = reinterpret_cast<const float*>(vertex + mOffsets[VATTR_TEXCOORD]);
|
||||
const uint8_t *attrColor = reinterpret_cast<const uint8_t*>(vertex + mOffsets[VATTR_COLOR]);
|
||||
const uint32_t* attrNormal = reinterpret_cast<const uint32_t*>(vertex + mOffsets[VATTR_NORMAL]);
|
||||
const uint32_t* attrNormal2 = reinterpret_cast<const uint32_t*>(vertex + mOffsets[VATTR_NORMAL2]);
|
||||
|
||||
thread->mainVertexShader.aPosition = { attrVertex[0], attrVertex[1], attrVertex[2], 1.0f };
|
||||
thread->mainVertexShader.aTexCoord = { attrTexcoord[0], attrTexcoord[1] };
|
||||
|
||||
if ((UseVertexData & 1) == 0)
|
||||
{
|
||||
const auto &c = thread->mainVertexShader.Data.uVertexColor;
|
||||
thread->mainVertexShader.aColor.X = c.X;
|
||||
thread->mainVertexShader.aColor.Y = c.Y;
|
||||
thread->mainVertexShader.aColor.Z = c.Z;
|
||||
thread->mainVertexShader.aColor.W = c.W;
|
||||
}
|
||||
else
|
||||
{
|
||||
thread->mainVertexShader.aColor.X = attrColor[0] * (1.0f / 255.0f);
|
||||
thread->mainVertexShader.aColor.Y = attrColor[1] * (1.0f / 255.0f);
|
||||
thread->mainVertexShader.aColor.Z = attrColor[2] * (1.0f / 255.0f);
|
||||
thread->mainVertexShader.aColor.W = attrColor[3] * (1.0f / 255.0f);
|
||||
}
|
||||
|
||||
if ((UseVertexData & 2) == 0)
|
||||
{
|
||||
const auto &n = thread->mainVertexShader.Data.uVertexNormal;
|
||||
thread->mainVertexShader.aNormal = FVector4(n.X, n.Y, n.Z, 1.0);
|
||||
thread->mainVertexShader.aNormal2 = thread->mainVertexShader.aNormal;
|
||||
}
|
||||
else
|
||||
{
|
||||
int n = *attrNormal;
|
||||
int n2 = *attrNormal2;
|
||||
float x = ((n << 22) >> 22) / 512.0f;
|
||||
float y = ((n << 12) >> 22) / 512.0f;
|
||||
float z = ((n << 2) >> 22) / 512.0f;
|
||||
float x2 = ((n2 << 22) >> 22) / 512.0f;
|
||||
float y2 = ((n2 << 12) >> 22) / 512.0f;
|
||||
float z2 = ((n2 << 2) >> 22) / 512.0f;
|
||||
thread->mainVertexShader.aNormal = FVector4(x, y, z, 0.0f);
|
||||
thread->mainVertexShader.aNormal2 = FVector4(x2, y2, z2, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void PolyDataBuffer::BindRange(FRenderState *state, size_t start, size_t length)
|
||||
{
|
||||
static_cast<PolyRenderState*>(state)->Bind(this, (uint32_t)start, (uint32_t)length);
|
||||
}
|
79
source/common/rendering/polyrenderer/backend/poly_buffers.h
Normal file
79
source/common/rendering/polyrenderer/backend/poly_buffers.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
#pragma once
|
||||
|
||||
#include "hwrenderer/data/buffers.h"
|
||||
#include "polyrenderer/drawers/poly_triangle.h"
|
||||
#include "tarray.h"
|
||||
#include <vector>
|
||||
|
||||
#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
|
||||
|
||||
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<uint32_t> mData;
|
||||
};
|
||||
|
||||
class PolyVertexInputAssembly final : public PolyInputAssembly
|
||||
{
|
||||
public:
|
||||
size_t mOffsets[VATTR_MAX] = {};
|
||||
size_t mStride = 0;
|
||||
|
||||
int NumBindingPoints;
|
||||
size_t Stride;
|
||||
std::vector<FVertexBufferAttribute> Attrs;
|
||||
int UseVertexData;
|
||||
|
||||
void Load(PolyTriangleThreadData *thread, const void *vertices, int index) override;
|
||||
};
|
||||
|
||||
class PolyVertexBuffer : public IVertexBuffer, public PolyBuffer
|
||||
{
|
||||
public:
|
||||
PolyVertexBuffer() { }
|
||||
void SetFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs) override;
|
||||
|
||||
PolyVertexInputAssembly *VertexFormat = nullptr;
|
||||
};
|
||||
|
||||
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(FRenderState *state, size_t start, size_t length) override;
|
||||
|
||||
int bindingpoint;
|
||||
};
|
|
@ -0,0 +1,430 @@
|
|||
/*
|
||||
** Softpoly backend
|
||||
** Copyright (c) 2016-2020 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include "v_video.h"
|
||||
#include "m_png.h"
|
||||
#include "templates.h"
|
||||
#include "r_videoscale.h"
|
||||
#include "i_time.h"
|
||||
#include "v_text.h"
|
||||
#include "i_video.h"
|
||||
#include "v_draw.h"
|
||||
#include "colormaps.h"
|
||||
|
||||
#include "hw_clock.h"
|
||||
#include "hw_vrmodes.h"
|
||||
#include "hw_cvars.h"
|
||||
#include "hw_skydome.h"
|
||||
#include "hwrenderer/data/hw_viewpointbuffer.h"
|
||||
#include "flatvertices.h"
|
||||
#include "hwrenderer/data/shaderuniforms.h"
|
||||
#include "hw_lightbuffer.h"
|
||||
#include "hwrenderer/postprocessing/hw_postprocess.h"
|
||||
|
||||
#include "poly_framebuffer.h"
|
||||
#include "poly_buffers.h"
|
||||
#include "poly_renderstate.h"
|
||||
#include "poly_hwtexture.h"
|
||||
#include "engineerrors.h"
|
||||
|
||||
void Draw2D(F2DDrawer *drawer, FRenderState &state);
|
||||
|
||||
extern int rendered_commandbuffers;
|
||||
extern int current_rendered_commandbuffers;
|
||||
|
||||
extern bool gpuStatActive;
|
||||
extern bool keepGpuStatActive;
|
||||
extern FString gpuStatOutput;
|
||||
|
||||
PolyFrameBuffer::PolyFrameBuffer(void *hMonitor, bool fullscreen) : Super(hMonitor, fullscreen)
|
||||
{
|
||||
I_PolyPresentInit();
|
||||
}
|
||||
|
||||
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 mScreenQuad.VertexBuffer;
|
||||
delete mScreenQuad.IndexBuffer;
|
||||
|
||||
delete mVertexData;
|
||||
delete mSkyData;
|
||||
delete mViewpoints;
|
||||
delete mLights;
|
||||
mShadowMap.Reset();
|
||||
|
||||
screen = tmp;
|
||||
|
||||
I_PolyPresentDeinit();
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::InitializeState()
|
||||
{
|
||||
vendorstring = "Poly";
|
||||
hwcaps = RFL_SHADER_STORAGE_BUFFER | RFL_BUFFER_STORAGE;
|
||||
glslversion = 4.50f;
|
||||
uniformblockalignment = 1;
|
||||
maxuniformblock = 0x7fffffff;
|
||||
|
||||
mRenderState.reset(new PolyRenderState());
|
||||
|
||||
mVertexData = new FFlatVertexBuffer(GetWidth(), GetHeight());
|
||||
mSkyData = new FSkyVertexBuffer;
|
||||
mViewpoints = new HWViewpointBuffer;
|
||||
mLights = new FLightBuffer();
|
||||
|
||||
static const FVertexBufferAttribute format[] =
|
||||
{
|
||||
{ 0, VATTR_VERTEX, VFmt_Float3, (int)myoffsetof(ScreenQuadVertex, x) },
|
||||
{ 0, VATTR_TEXCOORD, VFmt_Float2, (int)myoffsetof(ScreenQuadVertex, u) },
|
||||
{ 0, VATTR_COLOR, VFmt_Byte4, (int)myoffsetof(ScreenQuadVertex, color0) }
|
||||
};
|
||||
|
||||
uint32_t indices[6] = { 0, 1, 2, 1, 3, 2 };
|
||||
|
||||
mScreenQuad.VertexBuffer = screen->CreateVertexBuffer();
|
||||
mScreenQuad.VertexBuffer->SetFormat(1, 3, sizeof(ScreenQuadVertex), format);
|
||||
|
||||
mScreenQuad.IndexBuffer = screen->CreateIndexBuffer();
|
||||
mScreenQuad.IndexBuffer->SetData(6 * sizeof(uint32_t), indices, false);
|
||||
|
||||
CheckCanvas();
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::CheckCanvas()
|
||||
{
|
||||
if (!mCanvas || mCanvas->GetWidth() != GetWidth() || mCanvas->GetHeight() != GetHeight())
|
||||
{
|
||||
FlushDrawCommands();
|
||||
DrawerThreads::WaitForWorkers();
|
||||
|
||||
mCanvas.reset(new DCanvas(0, 0, true));
|
||||
mCanvas->Resize(GetWidth(), GetHeight(), false);
|
||||
mDepthStencil.reset();
|
||||
mDepthStencil.reset(new PolyDepthStencil(GetWidth(), GetHeight()));
|
||||
|
||||
mRenderState->SetRenderTarget(GetCanvas(), GetDepthStencil(), true);
|
||||
}
|
||||
}
|
||||
|
||||
PolyCommandBuffer *PolyFrameBuffer::GetDrawCommands()
|
||||
{
|
||||
if (!mDrawCommands)
|
||||
{
|
||||
mDrawCommands.reset(new PolyCommandBuffer(&mFrameMemory));
|
||||
mDrawCommands->SetLightBuffer(mLightBuffer->Memory());
|
||||
}
|
||||
return mDrawCommands.get();
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::FlushDrawCommands()
|
||||
{
|
||||
mRenderState->EndRenderPass();
|
||||
if (mDrawCommands)
|
||||
{
|
||||
mDrawCommands->Submit();
|
||||
mDrawCommands.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::Update()
|
||||
{
|
||||
twoD.Reset();
|
||||
Flush3D.Reset();
|
||||
|
||||
Flush3D.Clock();
|
||||
|
||||
Draw2D();
|
||||
twod->Clear();
|
||||
|
||||
Flush3D.Unclock();
|
||||
|
||||
FlushDrawCommands();
|
||||
|
||||
if (mCanvas)
|
||||
{
|
||||
int w = mCanvas->GetWidth();
|
||||
int h = mCanvas->GetHeight();
|
||||
int pixelsize = 4;
|
||||
const uint8_t *src = (const uint8_t*)mCanvas->GetPixels();
|
||||
int pitch = 0;
|
||||
uint8_t *dst = I_PolyPresentLock(w, h, cur_vsync, pitch);
|
||||
if (dst)
|
||||
{
|
||||
#if 1
|
||||
auto copyqueue = std::make_shared<DrawerCommandQueue>(&mFrameMemory);
|
||||
copyqueue->Push<MemcpyCommand>(dst, pitch / pixelsize, src, w, h, w, pixelsize);
|
||||
DrawerThreads::Execute(copyqueue);
|
||||
#else
|
||||
for (int y = 0; y < h; y++)
|
||||
{
|
||||
memcpy(dst + y * pitch, src + y * w * pixelsize, w * pixelsize);
|
||||
}
|
||||
#endif
|
||||
|
||||
DrawerThreads::WaitForWorkers();
|
||||
I_PolyPresentUnlock(mOutputLetterbox.left, mOutputLetterbox.top, mOutputLetterbox.width, mOutputLetterbox.height);
|
||||
}
|
||||
FPSLimit();
|
||||
}
|
||||
|
||||
DrawerThreads::WaitForWorkers();
|
||||
mFrameMemory.Clear();
|
||||
FrameDeleteList.Buffers.clear();
|
||||
FrameDeleteList.Images.clear();
|
||||
|
||||
CheckCanvas();
|
||||
|
||||
Super::Update();
|
||||
}
|
||||
|
||||
|
||||
void PolyFrameBuffer::RenderTextureView(FCanvasTexture* tex, std::function<void(IntRect &)> renderFunc)
|
||||
{
|
||||
auto BaseLayer = static_cast<PolyHardwareTexture*>(tex->GetHardwareTexture(0, 0));
|
||||
|
||||
DCanvas *image = BaseLayer->GetImage(tex, 0, 0);
|
||||
PolyDepthStencil *depthStencil = BaseLayer->GetDepthStencil(tex);
|
||||
mRenderState->SetRenderTarget(image, depthStencil, false);
|
||||
|
||||
IntRect bounds;
|
||||
bounds.left = bounds.top = 0;
|
||||
bounds.width = std::min(tex->GetWidth(), image->GetWidth());
|
||||
bounds.height = std::min(tex->GetHeight(), image->GetHeight());
|
||||
|
||||
renderFunc(bounds);
|
||||
|
||||
FlushDrawCommands();
|
||||
DrawerThreads::WaitForWorkers();
|
||||
mRenderState->SetRenderTarget(GetCanvas(), GetDepthStencil(), true);
|
||||
|
||||
tex->SetUpdated(true);
|
||||
}
|
||||
|
||||
static uint8_t ToIntColorComponent(float v)
|
||||
{
|
||||
return clamp((int)(v * 255.0f + 0.5f), 0, 255);
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::PostProcessScene(bool swscene, int fixedcm, const std::function<void()> &afterBloomDrawEndScene2D)
|
||||
{
|
||||
afterBloomDrawEndScene2D();
|
||||
|
||||
if (fixedcm >= CM_FIRSTSPECIALCOLORMAP && fixedcm < CM_MAXCOLORMAP)
|
||||
{
|
||||
FSpecialColormap* scm = &SpecialColormaps[fixedcm - CM_FIRSTSPECIALCOLORMAP];
|
||||
|
||||
mRenderState->SetViewport(mScreenViewport.left, mScreenViewport.top, mScreenViewport.width, mScreenViewport.height);
|
||||
screen->mViewpoints->Set2D(*mRenderState, screen->GetWidth(), screen->GetHeight());
|
||||
|
||||
ScreenQuadVertex vertices[4] =
|
||||
{
|
||||
{ 0.0f, 0.0f, 0.0f, 0.0f },
|
||||
{ (float)mScreenViewport.width, 0.0f, 1.0f, 0.0f },
|
||||
{ 0.0f, (float)mScreenViewport.height, 0.0f, 1.0f },
|
||||
{ (float)mScreenViewport.width, (float)mScreenViewport.height, 1.0f, 1.0f }
|
||||
};
|
||||
mScreenQuad.VertexBuffer->SetData(4 * sizeof(ScreenQuadVertex), vertices, false);
|
||||
|
||||
mRenderState->SetVertexBuffer(mScreenQuad.VertexBuffer, 0, 0);
|
||||
mRenderState->SetIndexBuffer(mScreenQuad.IndexBuffer);
|
||||
|
||||
mRenderState->SetObjectColor(PalEntry(255, int(scm->ColorizeStart[0] * 127.5f), int(scm->ColorizeStart[1] * 127.5f), int(scm->ColorizeStart[2] * 127.5f)));
|
||||
mRenderState->SetAddColor(PalEntry(255, int(scm->ColorizeEnd[0] * 127.5f), int(scm->ColorizeEnd[1] * 127.5f), int(scm->ColorizeEnd[2] * 127.5f)));
|
||||
|
||||
mRenderState->EnableDepthTest(false);
|
||||
mRenderState->EnableMultisampling(false);
|
||||
mRenderState->SetCulling(Cull_None);
|
||||
|
||||
mRenderState->SetScissor(-1, -1, -1, -1);
|
||||
mRenderState->SetColor(1, 1, 1, 1);
|
||||
mRenderState->AlphaFunc(Alpha_GEqual, 0.f);
|
||||
mRenderState->EnableTexture(false);
|
||||
mRenderState->SetColormapShader(true);
|
||||
mRenderState->DrawIndexed(DT_Triangles, 0, 6);
|
||||
mRenderState->SetColormapShader(false);
|
||||
mRenderState->SetObjectColor(0xffffffff);
|
||||
mRenderState->SetAddColor(0);
|
||||
mRenderState->SetVertexBuffer(screen->mVertexData);
|
||||
mRenderState->EnableTexture(true);
|
||||
mRenderState->ResetColor();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PolyFrameBuffer::SetVSync(bool vsync)
|
||||
{
|
||||
cur_vsync = vsync;
|
||||
}
|
||||
|
||||
FRenderState* PolyFrameBuffer::RenderState()
|
||||
{
|
||||
return mRenderState.get();
|
||||
}
|
||||
|
||||
|
||||
void PolyFrameBuffer::PrecacheMaterial(FMaterial *mat, int translation)
|
||||
{
|
||||
if (mat->Source()->GetUseType() == ETextureType::SWCanvas) return;
|
||||
|
||||
MaterialLayerInfo* layer;
|
||||
auto systex = static_cast<PolyHardwareTexture*>(mat->GetLayer(0, translation, &layer));
|
||||
systex->GetImage(layer->layerTexture, translation, layer->scaleFlags);
|
||||
|
||||
int numLayers = mat->NumLayers();
|
||||
for (int i = 1; i < numLayers; i++)
|
||||
{
|
||||
auto systex = static_cast<PolyHardwareTexture*>(mat->GetLayer(i, 0, &layer));
|
||||
systex->GetImage(layer->layerTexture, 0, layer->scaleFlags); // fixme: Upscale flags must be disabled for certain layers.
|
||||
}
|
||||
}
|
||||
|
||||
IHardwareTexture *PolyFrameBuffer::CreateHardwareTexture(int)
|
||||
{
|
||||
return new PolyHardwareTexture();
|
||||
}
|
||||
|
||||
IVertexBuffer *PolyFrameBuffer::CreateVertexBuffer()
|
||||
{
|
||||
return new PolyVertexBuffer();
|
||||
}
|
||||
|
||||
IIndexBuffer *PolyFrameBuffer::CreateIndexBuffer()
|
||||
{
|
||||
return new PolyIndexBuffer();
|
||||
}
|
||||
|
||||
IDataBuffer *PolyFrameBuffer::CreateDataBuffer(int bindingpoint, bool ssbo, bool needsresize)
|
||||
{
|
||||
IDataBuffer *buffer = new PolyDataBuffer(bindingpoint, ssbo, needsresize);
|
||||
if (bindingpoint == LIGHTBUF_BINDINGPOINT)
|
||||
mLightBuffer = buffer;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::SetTextureFilterMode()
|
||||
{
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::BlurScene(float amount)
|
||||
{
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::UpdatePalette()
|
||||
{
|
||||
}
|
||||
|
||||
FTexture *PolyFrameBuffer::WipeStartScreen()
|
||||
{
|
||||
SetViewportRects(nullptr);
|
||||
|
||||
auto tex = new FWrapperTexture(mScreenViewport.width, mScreenViewport.height, 1);
|
||||
auto systex = static_cast<PolyHardwareTexture*>(tex->GetSystemTexture());
|
||||
|
||||
systex->CreateWipeTexture(mScreenViewport.width, mScreenViewport.height, "WipeStartScreen");
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
FTexture *PolyFrameBuffer::WipeEndScreen()
|
||||
{
|
||||
Draw2D();
|
||||
twod->Clear();
|
||||
|
||||
auto tex = new FWrapperTexture(mScreenViewport.width, mScreenViewport.height, 1);
|
||||
auto systex = static_cast<PolyHardwareTexture*>(tex->GetSystemTexture());
|
||||
|
||||
systex->CreateWipeTexture(mScreenViewport.width, mScreenViewport.height, "WipeEndScreen");
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
TArray<uint8_t> PolyFrameBuffer::GetScreenshotBuffer(int &pitch, ESSType &color_type, float &gamma)
|
||||
{
|
||||
int w = SCREENWIDTH;
|
||||
int h = SCREENHEIGHT;
|
||||
|
||||
TArray<uint8_t> ScreenshotBuffer(w * h * 3, true);
|
||||
const uint8_t* pixels = GetCanvas()->GetPixels();
|
||||
int dindex = 0;
|
||||
|
||||
// Convert to RGB
|
||||
for (int y = 0; y < h; y++)
|
||||
{
|
||||
int sindex = y * w * 4;
|
||||
|
||||
for (int x = 0; x < w; x++)
|
||||
{
|
||||
ScreenshotBuffer[dindex ] = pixels[sindex + 2];
|
||||
ScreenshotBuffer[dindex + 1] = pixels[sindex + 1];
|
||||
ScreenshotBuffer[dindex + 2] = pixels[sindex ];
|
||||
dindex += 3;
|
||||
sindex += 4;
|
||||
}
|
||||
}
|
||||
|
||||
pitch = w * 3;
|
||||
color_type = SS_RGB;
|
||||
gamma = 1.0f;
|
||||
return ScreenshotBuffer;
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::BeginFrame()
|
||||
{
|
||||
SetViewportRects(nullptr);
|
||||
CheckCanvas();
|
||||
|
||||
#if 0
|
||||
swrenderer::R_InitFuzzTable(GetCanvas()->GetPitch());
|
||||
static int next_random = 0;
|
||||
swrenderer::fuzzpos = (swrenderer::fuzzpos + swrenderer::fuzz_random_x_offset[next_random] * FUZZTABLE / 100) % FUZZTABLE;
|
||||
next_random++;
|
||||
if (next_random == FUZZ_RANDOM_X_SIZE)
|
||||
next_random = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::Draw2D()
|
||||
{
|
||||
::Draw2D(twod, *mRenderState);
|
||||
}
|
||||
|
||||
unsigned int PolyFrameBuffer::GetLightBufferBlockSize() const
|
||||
{
|
||||
return mLights->GetBlockSize();
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::UpdateShadowMap()
|
||||
{
|
||||
}
|
||||
|
||||
void PolyFrameBuffer::AmbientOccludeScene(float m5)
|
||||
{
|
||||
//mPostprocess->AmbientOccludeScene(m5);
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
#pragma once
|
||||
|
||||
#include "gl_sysfb.h"
|
||||
#include "r_memory.h"
|
||||
#include "r_thread.h"
|
||||
#include "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(); }
|
||||
DCanvas *GetCanvas() override { return mCanvas.get(); }
|
||||
PolyDepthStencil *GetDepthStencil() { return mDepthStencil.get(); }
|
||||
PolyCommandBuffer *GetDrawCommands();
|
||||
void FlushDrawCommands();
|
||||
|
||||
unsigned int GetLightBufferBlockSize() const;
|
||||
|
||||
PolyFrameBuffer(void *hMonitor, bool fullscreen);
|
||||
~PolyFrameBuffer();
|
||||
|
||||
void Update() override;
|
||||
|
||||
bool IsPoly() override { return true; }
|
||||
|
||||
void InitializeState() override;
|
||||
|
||||
FRenderState* RenderState() override;
|
||||
void PrecacheMaterial(FMaterial *mat, int translation) override;
|
||||
void UpdatePalette() override;
|
||||
void SetTextureFilterMode() override;
|
||||
void BeginFrame() override;
|
||||
void BlurScene(float amount) override;
|
||||
void PostProcessScene(bool swscene, int fixedcm, const std::function<void()> &afterBloomDrawEndScene2D) override;
|
||||
void AmbientOccludeScene(float m5) override;
|
||||
//void SetSceneRenderTarget(bool useSSAO) override;
|
||||
|
||||
IHardwareTexture *CreateHardwareTexture(int) override;
|
||||
IVertexBuffer *CreateVertexBuffer() override;
|
||||
IIndexBuffer *CreateIndexBuffer() override;
|
||||
IDataBuffer *CreateDataBuffer(int bindingpoint, bool ssbo, bool needsresize) override;
|
||||
|
||||
FTexture *WipeStartScreen() override;
|
||||
FTexture *WipeEndScreen() override;
|
||||
|
||||
TArray<uint8_t> GetScreenshotBuffer(int &pitch, ESSType &color_type, float &gamma) override;
|
||||
|
||||
void SetVSync(bool vsync) override;
|
||||
void Draw2D() override;
|
||||
|
||||
struct DeleteList
|
||||
{
|
||||
std::vector<std::vector<uint32_t>> Buffers;
|
||||
std::vector<std::unique_ptr<DCanvas>> Images;
|
||||
} FrameDeleteList;
|
||||
|
||||
private:
|
||||
void RenderTextureView(FCanvasTexture* tex, std::function<void(IntRect &)> renderFunc) override;
|
||||
void UpdateShadowMap() override;
|
||||
|
||||
void CheckCanvas();
|
||||
|
||||
IDataBuffer *mLightBuffer = nullptr;
|
||||
|
||||
std::unique_ptr<PolyRenderState> mRenderState;
|
||||
std::unique_ptr<DCanvas> mCanvas;
|
||||
std::unique_ptr<PolyDepthStencil> mDepthStencil;
|
||||
std::unique_ptr<PolyCommandBuffer> mDrawCommands;
|
||||
RenderMemory mFrameMemory;
|
||||
|
||||
struct ScreenQuadVertex
|
||||
{
|
||||
float x, y, z;
|
||||
float u, v;
|
||||
PalEntry color0;
|
||||
|
||||
ScreenQuadVertex() = default;
|
||||
ScreenQuadVertex(float x, float y, float u, float v) : x(x), y(y), z(1.0f), u(u), v(v), color0(0xffffffff) { }
|
||||
};
|
||||
|
||||
struct ScreenQuad
|
||||
{
|
||||
IVertexBuffer* VertexBuffer = nullptr;
|
||||
IIndexBuffer* IndexBuffer = nullptr;
|
||||
} mScreenQuad;
|
||||
|
||||
bool cur_vsync = false;
|
||||
};
|
||||
|
||||
inline PolyFrameBuffer *GetPolyFrameBuffer() { return static_cast<PolyFrameBuffer*>(screen); }
|
143
source/common/rendering/polyrenderer/backend/poly_hwtexture.cpp
Normal file
143
source/common/rendering/polyrenderer/backend/poly_hwtexture.cpp
Normal file
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
** Softpoly backend
|
||||
** Copyright (c) 2016-2020 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include "templates.h"
|
||||
#include "c_cvars.h"
|
||||
#include "hw_material.h"
|
||||
#include "hw_cvars.h"
|
||||
#include "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()
|
||||
{
|
||||
if (auto fb = GetPolyFrameBuffer())
|
||||
{
|
||||
auto &deleteList = fb->FrameDeleteList;
|
||||
if (mCanvas) deleteList.Images.push_back(std::move(mCanvas));
|
||||
}
|
||||
}
|
||||
|
||||
DCanvas *PolyHardwareTexture::GetImage(FTexture *tex, int translation, int flags)
|
||||
{
|
||||
if (!mCanvas)
|
||||
CreateImage(tex, translation, flags);
|
||||
return mCanvas.get();
|
||||
}
|
||||
|
||||
PolyDepthStencil *PolyHardwareTexture::GetDepthStencil(FTexture *tex)
|
||||
{
|
||||
if (!mDepthStencil)
|
||||
{
|
||||
int w = tex->GetWidth();
|
||||
int h = tex->GetHeight();
|
||||
mDepthStencil.reset(new PolyDepthStencil(w, h));
|
||||
}
|
||||
return mDepthStencil.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);
|
||||
bufferpitch = mCanvas->GetPitch();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *PolyHardwareTexture::MapBuffer()
|
||||
{
|
||||
return mCanvas->GetPixels();
|
||||
}
|
||||
|
||||
unsigned int PolyHardwareTexture::CreateTexture(unsigned char * buffer, int w, int h, int texunit, bool mipmap, 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);
|
||||
}
|
||||
|
||||
auto fb = static_cast<PolyFrameBuffer*>(screen);
|
||||
|
||||
fb->FlushDrawCommands();
|
||||
DrawerThreads::WaitForWorkers();
|
||||
|
||||
uint32_t* dest = (uint32_t*)mCanvas->GetPixels();
|
||||
uint32_t* src = (uint32_t*)fb->GetCanvas()->GetPixels();
|
||||
int dpitch = mCanvas->GetPitch();
|
||||
int spitch = fb->GetCanvas()->GetPitch();
|
||||
int pixelsize = 4;
|
||||
|
||||
for (int y = 0; y < h; y++)
|
||||
{
|
||||
memcpy(dest + dpitch * (h - 1 - y), src + spitch * y, w * pixelsize);
|
||||
}
|
||||
}
|
||||
|
||||
void PolyHardwareTexture::CreateImage(FTexture *tex, int translation, int flags)
|
||||
{
|
||||
mCanvas.reset(new DCanvas(0, 0, true));
|
||||
|
||||
if (!tex->isHardwareCanvas())
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef LoadImage
|
||||
#undef LoadImage
|
||||
#endif
|
||||
|
||||
#define SHADED_TEXTURE -1
|
||||
#define DIRECT_PALETTE -2
|
||||
|
||||
#include "tarray.h"
|
||||
#include "hw_ihwtexture.h"
|
||||
#include "volk/volk.h"
|
||||
|
||||
struct FMaterialState;
|
||||
class PolyBuffer;
|
||||
|
||||
class PolyHardwareTexture : public IHardwareTexture
|
||||
{
|
||||
public:
|
||||
PolyHardwareTexture();
|
||||
~PolyHardwareTexture();
|
||||
|
||||
static void ResetAll();
|
||||
void Reset();
|
||||
|
||||
DCanvas *GetImage(FTexture *tex, int translation, int flags);
|
||||
PolyDepthStencil *GetDepthStencil(FTexture *tex);
|
||||
|
||||
// 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, 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<DCanvas> mCanvas;
|
||||
std::unique_ptr<PolyDepthStencil> mDepthStencil;
|
||||
};
|
|
@ -0,0 +1,444 @@
|
|||
/*
|
||||
** Softpoly backend
|
||||
** Copyright (c) 2016-2020 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include "polyrenderer/backend/poly_renderstate.h"
|
||||
#include "polyrenderer/backend/poly_framebuffer.h"
|
||||
#include "polyrenderer/backend/poly_hwtexture.h"
|
||||
#include "templates.h"
|
||||
#include "hw_skydome.h"
|
||||
#include "hw_viewpointuniforms.h"
|
||||
#include "hw_lightbuffer.h"
|
||||
#include "hw_cvars.h"
|
||||
#include "hw_clock.h"
|
||||
#include "flatvertices.h"
|
||||
#include "hwrenderer/data/hw_viewpointbuffer.h"
|
||||
#include "hwrenderer/data/shaderuniforms.h"
|
||||
|
||||
static PolyDrawMode dtToDrawMode[] =
|
||||
{
|
||||
PolyDrawMode::Points,
|
||||
PolyDrawMode::Lines,
|
||||
PolyDrawMode::Triangles,
|
||||
PolyDrawMode::TriangleFan,
|
||||
PolyDrawMode::TriangleStrip,
|
||||
};
|
||||
|
||||
PolyRenderState::PolyRenderState()
|
||||
{
|
||||
mIdentityMatrix.loadIdentity();
|
||||
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 || mNeedApply)
|
||||
Apply();
|
||||
|
||||
mDrawCommands->Draw(index, count, dtToDrawMode[dt]);
|
||||
}
|
||||
|
||||
void PolyRenderState::DrawIndexed(int dt, int index, int count, bool apply)
|
||||
{
|
||||
if (apply || mNeedApply)
|
||||
Apply();
|
||||
|
||||
mDrawCommands->DrawIndexed(index, count, dtToDrawMode[dt]);
|
||||
}
|
||||
|
||||
bool PolyRenderState::SetDepthClamp(bool on)
|
||||
{
|
||||
bool lastValue = mDepthClamp;
|
||||
mDepthClamp = on;
|
||||
mNeedApply = true;
|
||||
return lastValue;
|
||||
}
|
||||
|
||||
void PolyRenderState::SetDepthMask(bool on)
|
||||
{
|
||||
mDepthMask = on;
|
||||
mNeedApply = true;
|
||||
}
|
||||
|
||||
void PolyRenderState::SetDepthFunc(int func)
|
||||
{
|
||||
mDepthFunc = func;
|
||||
mNeedApply = true;
|
||||
}
|
||||
|
||||
void PolyRenderState::SetDepthRange(float min, float max)
|
||||
{
|
||||
mDepthRangeMin = min;
|
||||
mDepthRangeMax = max;
|
||||
mNeedApply = true;
|
||||
}
|
||||
|
||||
void PolyRenderState::SetColorMask(bool r, bool g, bool b, bool a)
|
||||
{
|
||||
mColorMask[0] = r;
|
||||
mColorMask[1] = g;
|
||||
mColorMask[2] = b;
|
||||
mColorMask[3] = a;
|
||||
mNeedApply = true;
|
||||
}
|
||||
|
||||
void PolyRenderState::SetStencil(int offs, int op, int flags)
|
||||
{
|
||||
mStencilValue = screen->stencilValue + offs;
|
||||
mStencilOp = op;
|
||||
mNeedApply = true;
|
||||
|
||||
if (flags != -1)
|
||||
{
|
||||
bool cmon = !(flags & SF_ColorMaskOff);
|
||||
SetColorMask(cmon, cmon, cmon, cmon); // don't write to the graphics buffer
|
||||
SetDepthMask(!(flags & SF_DepthMaskOff));
|
||||
}
|
||||
}
|
||||
|
||||
void PolyRenderState::SetCulling(int mode)
|
||||
{
|
||||
mCulling = mode;
|
||||
mNeedApply = true;
|
||||
}
|
||||
|
||||
void PolyRenderState::EnableClipDistance(int num, bool state)
|
||||
{
|
||||
}
|
||||
|
||||
void PolyRenderState::Clear(int targets)
|
||||
{
|
||||
if (mNeedApply)
|
||||
Apply();
|
||||
|
||||
//if (targets & CT_Color)
|
||||
// mDrawCommands->ClearColor();
|
||||
if (targets & CT_Depth)
|
||||
mDrawCommands->ClearDepth(65535.0f);
|
||||
if (targets & CT_Stencil)
|
||||
mDrawCommands->ClearStencil(0);
|
||||
}
|
||||
|
||||
void PolyRenderState::EnableStencil(bool on)
|
||||
{
|
||||
mStencilEnabled = on;
|
||||
mNeedApply = true;
|
||||
}
|
||||
|
||||
void PolyRenderState::SetScissor(int x, int y, int w, int h)
|
||||
{
|
||||
if (w < 0)
|
||||
{
|
||||
x = 0;
|
||||
y = 0;
|
||||
w = mRenderTarget.Canvas->GetWidth();
|
||||
h = mRenderTarget.Canvas->GetHeight();
|
||||
}
|
||||
mScissor.x = x;
|
||||
mScissor.y = mRenderTarget.Canvas->GetHeight() - y - h;
|
||||
mScissor.width = w;
|
||||
mScissor.height = h;
|
||||
mNeedApply = true;
|
||||
}
|
||||
|
||||
void PolyRenderState::SetViewport(int x, int y, int w, int h)
|
||||
{
|
||||
auto fb = GetPolyFrameBuffer();
|
||||
if (w < 0)
|
||||
{
|
||||
x = 0;
|
||||
y = 0;
|
||||
w = mRenderTarget.Canvas->GetWidth();
|
||||
h = mRenderTarget.Canvas->GetHeight();
|
||||
}
|
||||
mViewport.x = x;
|
||||
mViewport.y = mRenderTarget.Canvas->GetHeight() - y - h;
|
||||
mViewport.width = w;
|
||||
mViewport.height = h;
|
||||
mNeedApply = true;
|
||||
}
|
||||
|
||||
void PolyRenderState::EnableDepthTest(bool on)
|
||||
{
|
||||
mDepthTest = on;
|
||||
mNeedApply = true;
|
||||
}
|
||||
|
||||
void PolyRenderState::EnableMultisampling(bool on)
|
||||
{
|
||||
}
|
||||
|
||||
void PolyRenderState::EnableLineSmooth(bool on)
|
||||
{
|
||||
}
|
||||
|
||||
void PolyRenderState::EnableDrawBuffers(int count, bool apply)
|
||||
{
|
||||
}
|
||||
|
||||
void PolyRenderState::SetColormapShader(bool enable)
|
||||
{
|
||||
mNeedApply = true;
|
||||
mColormapShader = enable;
|
||||
}
|
||||
|
||||
void PolyRenderState::EndRenderPass()
|
||||
{
|
||||
mDrawCommands = nullptr;
|
||||
mNeedApply = true;
|
||||
mFirstMatrixApply = true;
|
||||
}
|
||||
|
||||
void PolyRenderState::Apply()
|
||||
{
|
||||
drawcalls.Clock();
|
||||
|
||||
if (!mDrawCommands)
|
||||
{
|
||||
mDrawCommands = GetPolyFrameBuffer()->GetDrawCommands();
|
||||
}
|
||||
|
||||
if (mNeedApply)
|
||||
{
|
||||
mDrawCommands->SetViewport(mViewport.x, mViewport.y, mViewport.width, mViewport.height, mRenderTarget.Canvas, mRenderTarget.DepthStencil, mRenderTarget.TopDown);
|
||||
mDrawCommands->SetScissor(mScissor.x, mScissor.y, mScissor.width, mScissor.height);
|
||||
mDrawCommands->SetViewpointUniforms(mViewpointUniforms);
|
||||
mDrawCommands->SetDepthClamp(mDepthClamp);
|
||||
mDrawCommands->SetDepthMask(mDepthTest && mDepthMask);
|
||||
mDrawCommands->SetDepthFunc(mDepthTest ? mDepthFunc : DF_Always);
|
||||
mDrawCommands->SetDepthRange(mDepthRangeMin, mDepthRangeMax);
|
||||
mDrawCommands->SetStencil(mStencilValue, mStencilOp);
|
||||
mDrawCommands->EnableStencil(mStencilEnabled);
|
||||
mDrawCommands->SetCulling(mCulling);
|
||||
mDrawCommands->SetColorMask(mColorMask[0], mColorMask[1], mColorMask[2], mColorMask[3]);
|
||||
mNeedApply = false;
|
||||
}
|
||||
|
||||
int fogset = 0;
|
||||
if (mFogEnabled)
|
||||
{
|
||||
if (mFogEnabled == 2)
|
||||
{
|
||||
fogset = -3; // 2D rendering with 'foggy' overlay.
|
||||
}
|
||||
else if ((GetFogColor() & 0xffffff) == 0)
|
||||
{
|
||||
fogset = gl_fogmode;
|
||||
}
|
||||
else
|
||||
{
|
||||
fogset = -gl_fogmode;
|
||||
}
|
||||
}
|
||||
|
||||
ApplyMaterial();
|
||||
|
||||
if (mVertexBuffer) mDrawCommands->SetVertexBuffer(mVertexBuffer->Memory());
|
||||
if (mIndexBuffer) mDrawCommands->SetIndexBuffer(mIndexBuffer->Memory());
|
||||
mDrawCommands->SetInputAssembly(static_cast<PolyVertexBuffer*>(mVertexBuffer)->VertexFormat);
|
||||
mDrawCommands->SetRenderStyle(mRenderStyle);
|
||||
|
||||
if (mColormapShader)
|
||||
{
|
||||
mDrawCommands->SetShader(EFF_NONE, 0, false, true);
|
||||
}
|
||||
else if (mSpecialEffect > EFF_NONE)
|
||||
{
|
||||
mDrawCommands->SetShader(mSpecialEffect, 0, false, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
int effectState = mMaterial.mOverrideShader >= 0 ? mMaterial.mOverrideShader : (mMaterial.mMaterial ? mMaterial.mMaterial->GetShaderIndex() : 0);
|
||||
mDrawCommands->SetShader(EFF_NONE, mTextureEnabled ? effectState : SHADER_NoTexture, mAlphaThreshold >= 0.f, false);
|
||||
}
|
||||
|
||||
if (mMaterial.mMaterial && mMaterial.mMaterial->Source())
|
||||
mStreamData.timer = static_cast<float>((double)(screen->FrameTime - firstFrame) * (double)mMaterial.mMaterial->Source()->GetShaderSpeed() / 1000.);
|
||||
else
|
||||
mStreamData.timer = 0.0f;
|
||||
|
||||
PolyPushConstants constants;
|
||||
constants.uFogEnabled = fogset;
|
||||
constants.uTextureMode = (mTextureMode == TM_NORMAL && mTempTM == TM_OPAQUE ? TM_OPAQUE : mTextureMode);
|
||||
constants.uLightDist = mLightParms[0];
|
||||
constants.uLightFactor = mLightParms[1];
|
||||
constants.uFogDensity = mLightParms[2];
|
||||
constants.uLightLevel = mLightParms[3];
|
||||
constants.uAlphaThreshold = mAlphaThreshold;
|
||||
constants.uClipSplit = { mClipSplit[0], mClipSplit[1] };
|
||||
constants.uLightIndex = mLightIndex;
|
||||
|
||||
mDrawCommands->PushStreamData(mStreamData, constants);
|
||||
ApplyMatrices();
|
||||
|
||||
if (mBias.mChanged)
|
||||
{
|
||||
mDrawCommands->SetDepthBias(mBias.mUnits, mBias.mFactor);
|
||||
mBias.mChanged = false;
|
||||
}
|
||||
|
||||
drawcalls.Unclock();
|
||||
}
|
||||
|
||||
void PolyRenderState::ApplyMaterial()
|
||||
{
|
||||
if (mMaterial.mChanged && mMaterial.mMaterial)
|
||||
{
|
||||
mTempTM = mMaterial.mMaterial->Source()->isHardwareCanvas() ? TM_OPAQUE : TM_NORMAL;
|
||||
|
||||
if (mMaterial.mMaterial->Source()->isHardwareCanvas()) static_cast<FCanvasTexture*>(mMaterial.mMaterial->Source()->GetTexture())->NeedUpdate();
|
||||
|
||||
MaterialLayerInfo* layer;
|
||||
auto base = static_cast<PolyHardwareTexture*>(mMaterial.mMaterial->GetLayer(0, mMaterial.mTranslation, &layer));
|
||||
if (base)
|
||||
{
|
||||
DCanvas *texcanvas = base->GetImage(layer->layerTexture, mMaterial.mTranslation, layer->scaleFlags);
|
||||
mDrawCommands->SetTexture(0, texcanvas->GetPixels(), texcanvas->GetWidth(), texcanvas->GetHeight(), texcanvas->IsBgra());
|
||||
|
||||
int numLayers = mMaterial.mMaterial->NumLayers();
|
||||
for (int i = 1; i < numLayers; i++)
|
||||
{
|
||||
auto systex = static_cast<PolyHardwareTexture*>(mMaterial.mMaterial->GetLayer(i, 0, &layer));
|
||||
|
||||
texcanvas = systex->GetImage(layer->layerTexture, 0, layer->scaleFlags);
|
||||
mDrawCommands->SetTexture(i, texcanvas->GetPixels(), texcanvas->GetWidth(), texcanvas->GetHeight(), texcanvas->IsBgra());
|
||||
}
|
||||
}
|
||||
|
||||
mMaterial.mChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void BufferedSet(bool &modified, T &dst, const T &src)
|
||||
{
|
||||
if (dst == src)
|
||||
return;
|
||||
dst = src;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
static void BufferedSet(bool &modified, VSMatrix &dst, const VSMatrix &src)
|
||||
{
|
||||
if (memcmp(dst.get(), src.get(), sizeof(FLOATTYPE) * 16) == 0)
|
||||
return;
|
||||
dst = src;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
void PolyRenderState::ApplyMatrices()
|
||||
{
|
||||
bool modified = mFirstMatrixApply;
|
||||
if (mTextureMatrixEnabled)
|
||||
{
|
||||
BufferedSet(modified, mMatrices.TextureMatrix, mTextureMatrix);
|
||||
}
|
||||
else
|
||||
{
|
||||
BufferedSet(modified, mMatrices.TextureMatrix, mIdentityMatrix);
|
||||
}
|
||||
|
||||
if (mModelMatrixEnabled)
|
||||
{
|
||||
BufferedSet(modified, mMatrices.ModelMatrix, mModelMatrix);
|
||||
if (modified)
|
||||
mMatrices.NormalModelMatrix.computeNormalMatrix(mModelMatrix);
|
||||
}
|
||||
else
|
||||
{
|
||||
BufferedSet(modified, mMatrices.ModelMatrix, mIdentityMatrix);
|
||||
BufferedSet(modified, mMatrices.NormalModelMatrix, mIdentityMatrix);
|
||||
}
|
||||
|
||||
if (modified)
|
||||
{
|
||||
mFirstMatrixApply = false;
|
||||
mDrawCommands->PushMatrices(mMatrices.ModelMatrix, mMatrices.NormalModelMatrix, mMatrices.TextureMatrix);
|
||||
}
|
||||
}
|
||||
|
||||
void PolyRenderState::SetRenderTarget(DCanvas *canvas, PolyDepthStencil *depthStencil, bool topdown)
|
||||
{
|
||||
mRenderTarget.Canvas = canvas;
|
||||
mRenderTarget.DepthStencil = depthStencil;
|
||||
mRenderTarget.TopDown = topdown;
|
||||
}
|
||||
|
||||
void PolyRenderState::Bind(PolyDataBuffer *buffer, uint32_t offset, uint32_t length)
|
||||
{
|
||||
if (buffer->bindingpoint == VIEWPOINT_BINDINGPOINT)
|
||||
{
|
||||
mViewpointUniforms = reinterpret_cast<HWViewpointUniforms*>(static_cast<uint8_t*>(buffer->Memory()) + offset);
|
||||
mNeedApply = true;
|
||||
}
|
||||
}
|
||||
|
||||
PolyVertexInputAssembly *PolyRenderState::GetVertexFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs)
|
||||
{
|
||||
for (size_t i = 0; i < mVertexFormats.size(); i++)
|
||||
{
|
||||
auto f = mVertexFormats[i].get();
|
||||
if (f->Attrs.size() == (size_t)numAttributes && f->NumBindingPoints == numBindingPoints && f->Stride == stride)
|
||||
{
|
||||
bool matches = true;
|
||||
for (int j = 0; j < numAttributes; j++)
|
||||
{
|
||||
if (memcmp(&f->Attrs[j], &attrs[j], sizeof(FVertexBufferAttribute)) != 0)
|
||||
{
|
||||
matches = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (matches)
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
auto fmt = std::make_unique<PolyVertexInputAssembly>();
|
||||
fmt->NumBindingPoints = numBindingPoints;
|
||||
fmt->Stride = stride;
|
||||
fmt->UseVertexData = 0;
|
||||
for (int j = 0; j < numAttributes; j++)
|
||||
{
|
||||
if (attrs[j].location == VATTR_COLOR)
|
||||
fmt->UseVertexData |= 1;
|
||||
else if (attrs[j].location == VATTR_NORMAL)
|
||||
fmt->UseVertexData |= 2;
|
||||
fmt->Attrs.push_back(attrs[j]);
|
||||
}
|
||||
|
||||
for (int j = 0; j < numAttributes; j++)
|
||||
{
|
||||
fmt->mOffsets[attrs[j].location] = attrs[j].offset;
|
||||
}
|
||||
fmt->mStride = stride;
|
||||
|
||||
mVertexFormats.push_back(std::move(fmt));
|
||||
return mVertexFormats.back().get();
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "polyrenderer/backend/poly_buffers.h"
|
||||
#include "poly_triangle.h"
|
||||
|
||||
#include "name.h"
|
||||
|
||||
#include "hw_renderstate.h"
|
||||
#include "hw_material.h"
|
||||
|
||||
struct HWViewpointUniforms;
|
||||
|
||||
class PolyRenderState final : 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, bool apply) override;
|
||||
|
||||
void SetRenderTarget(DCanvas *canvas, PolyDepthStencil *depthStencil, bool topdown);
|
||||
void Bind(PolyDataBuffer *buffer, uint32_t offset, uint32_t length);
|
||||
PolyVertexInputAssembly *GetVertexFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs);
|
||||
void EndRenderPass();
|
||||
|
||||
void SetColormapShader(bool enable);
|
||||
|
||||
private:
|
||||
void Apply();
|
||||
void ApplyMaterial();
|
||||
void ApplyMatrices();
|
||||
|
||||
struct Matrices
|
||||
{
|
||||
VSMatrix ModelMatrix;
|
||||
VSMatrix NormalModelMatrix;
|
||||
VSMatrix TextureMatrix;
|
||||
} mMatrices;
|
||||
VSMatrix mIdentityMatrix;
|
||||
bool mFirstMatrixApply = true;
|
||||
|
||||
HWViewpointUniforms *mViewpointUniforms = nullptr;
|
||||
std::vector<std::unique_ptr<PolyVertexInputAssembly>> mVertexFormats;
|
||||
|
||||
bool mDepthClamp = true;
|
||||
int mTempTM = TM_NORMAL;
|
||||
|
||||
struct RenderTarget
|
||||
{
|
||||
DCanvas *Canvas = nullptr;
|
||||
PolyDepthStencil *DepthStencil = nullptr;
|
||||
bool TopDown = true;
|
||||
} mRenderTarget;
|
||||
|
||||
struct Rect
|
||||
{
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
} mScissor, mViewport;
|
||||
|
||||
bool mNeedApply = true;
|
||||
|
||||
bool mDepthTest = false;
|
||||
bool mDepthMask = false;
|
||||
int mDepthFunc = DF_Always;
|
||||
float mDepthRangeMin = 0.0f;
|
||||
float mDepthRangeMax = 1.0f;
|
||||
bool mStencilEnabled = false;
|
||||
int mStencilValue = 0;
|
||||
int mStencilOp = SOP_Keep;
|
||||
int mCulling = Cull_None;
|
||||
bool mColorMask[4] = { true, true, true, true };
|
||||
bool mColormapShader = false;
|
||||
|
||||
PolyCommandBuffer* mDrawCommands = nullptr;
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue