Render scene with indexed textures for vid_rendermode 2

This commit is contained in:
Magnus Norddahl 2025-05-19 05:55:03 +02:00
commit 990ce7c6c9
28 changed files with 380 additions and 127 deletions

View file

@ -64,4 +64,17 @@ struct FColormap
};
struct FSWColormap
{
uint8_t* Maps = nullptr;
PalEntry Color = 0xffffffff;
PalEntry Fade = 0xff000000;
int Desaturate = 0;
struct
{
int textureIndex = -1;
int bindIndex = -1;
} Renderdev;
};

View file

@ -12,6 +12,7 @@ struct FMaterialState
int mTranslation = CLAMP_NONE;
int mOverrideShader = -1;
bool mChanged = false;
bool mPaletteMode = false;
GlobalShaderAddr globalShaderAddr = {0, 3, 0}; // null global shader entry, TODO
void Reset()
@ -21,6 +22,7 @@ struct FMaterialState
mClampMode = CLAMP_NONE;
mOverrideShader = -1;
mChanged = false;
mPaletteMode = false;
globalShaderAddr = {0, 3, 0};
}
};

View file

@ -16,6 +16,7 @@ struct FColormap;
class IBuffer;
struct HWViewpointUniforms;
struct FDynLightData;
struct FSWColormap;
enum class LevelMeshDrawType;
enum EClearTarget
@ -159,6 +160,9 @@ protected:
int mColorMapSpecial;
float mColorMapFlash;
bool mPaletteMode = false;
FSWColormap* mSWColormap = nullptr;
SurfaceUniforms mSurfaceUniforms = {};
PalEntry mFogColor;
@ -223,6 +227,8 @@ public:
mMaterial.Reset();
mBias.Reset();
mPassType = NORMAL_PASS;
mPaletteMode = false;
mSWColormap = nullptr;
mColorMapSpecial = 0;
mColorMapFlash = 1;
@ -621,6 +627,16 @@ public:
SetMaterial(tex, upscalemask, scaleflags, clampmode, translation.index(), overrideshader, cls);
}
void SetPaletteMode(bool palette)
{
mPaletteMode = palette;
}
void SetSWColormap(FSWColormap* cm)
{
mSWColormap = cm;
}
void SetClipSplit(float bottom, float top)
{
mSurfaceUniforms.uClipSplit.X = bottom;

View file

@ -44,10 +44,10 @@ struct SurfaceUniforms
float uAlphaThreshold;
int uTextureIndex;
float uDepthFadeThreshold;
int uColormapIndex;
int uLightProbeIndex;
FVector3 uActorCenter;
float padding2;
float uDepthFadeThreshold;
};
struct SurfaceLightUniforms

View file

@ -227,7 +227,7 @@ public:
virtual void SetActiveRenderTarget() {}
// Get the array index for the material in the textures array accessible from shaders
virtual int GetBindlessTextureIndex(FMaterial* material, int clampmode, int translation) { return -1; }
virtual int GetBindlessTextureIndex(FMaterial* material, int clampmode, int translation, bool paletteMode) { return -1; }
virtual void RenderEnvironmentMap(std::function<void(IntRect& bounds, int side)> renderFunc, TArrayView<uint16_t>& irradianceMap, TArrayView<uint16_t>& prefilterMap) {}
virtual void UploadEnvironmentMaps(int cubemapCount, const TArray<uint16_t>& irradianceMaps, const TArray<uint16_t>& prefilterMaps) {}

View file

@ -37,6 +37,7 @@
#include "flatvertices.h"
#include "hw_viewpointuniforms.h"
#include "v_2ddrawer.h"
#include "fcolormap.h"
VkDescriptorSetManager::VkDescriptorSetManager(VulkanRenderDevice* fb) : fb(fb)
{
@ -170,6 +171,10 @@ void VkDescriptorSetManager::ResetHWTextureSets()
for (auto mat : Materials)
mat->DeleteDescriptors();
for (FSWColormap* colormap : Colormaps)
colormap->Renderdev.bindIndex = -1;
Colormaps.clear();
Bindless.Writer = WriteDescriptors();
Bindless.NextIndex = 0;
@ -178,6 +183,9 @@ void VkDescriptorSetManager::ResetHWTextureSets()
// And slot 1 is always our BRDF LUT texture
AddBindlessTextureIndex(fb->GetTextureManager()->GetBrdfLutTextureView(), fb->GetSamplerManager()->Get(CLAMP_XY_NOMIP));
// Slot 2 is always our game palette texture
AddBindlessTextureIndex(fb->GetTextureManager()->GetGamePaletteView(), fb->GetSamplerManager()->Get(CLAMP_XY_NOMIP));
}
void VkDescriptorSetManager::AddMaterial(VkMaterial* texture)
@ -408,3 +416,13 @@ int VkDescriptorSetManager::AddBindlessTextureIndex(VulkanImageView* imageview,
Bindless.Writer.AddCombinedImageSampler(Bindless.Set.get(), 0, index, imageview, sampler, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
return index;
}
int VkDescriptorSetManager::GetSWColormapTextureIndex(FSWColormap* colormap)
{
if (colormap->Renderdev.bindIndex != -1)
return colormap->Renderdev.bindIndex;
colormap->Renderdev.bindIndex = AddBindlessTextureIndex(fb->GetTextureManager()->GetSWColormapView(colormap), fb->GetSamplerManager()->Get(CLAMP_XY_NOMIP));
Colormaps.push_back(colormap);
return colormap->Renderdev.bindIndex;
}

View file

@ -10,6 +10,7 @@ class VulkanRenderDevice;
class VkMaterial;
class PPTextureInput;
class VkPPRenderPassSetup;
struct FSWColormap;
class VkDescriptorSetManager
{
@ -44,6 +45,8 @@ public:
void UpdateBindlessDescriptorSet();
int AddBindlessTextureIndex(VulkanImageView* imageview, VulkanSampler* sampler);
int GetSWColormapTextureIndex(FSWColormap* colormap);
private:
void CreateLevelMeshLayout();
void CreateRSBufferLayout();
@ -115,6 +118,7 @@ private:
} ZMinMax;
std::list<VkMaterial*> Materials;
std::vector<FSWColormap*> Colormaps;
static const int MaxFixedSets = 100;
static const int MaxBindlessTextures = 16536;

View file

@ -464,6 +464,7 @@ void VkShaderManager::BuildDefinesBlock(FString &definesBlock, const char *defin
definesBlock << "#define LIGHT_ATTENUATION_INVERSE_SQUARE ((uShaderKey1 & SK1_LIGHTATTENUATIONMODE) != 0)\n";
definesBlock << "#define FOGBALLS ((uShaderKey1 & SK1_FOGBALLS) != 0)\n";
definesBlock << "#define PALETTEMODE ((uShaderKey1 & SK1_PALETTEMODE) != 0)\n";
definesBlock << "#define USE_DEPTHFADETHRESHOLD ((uShaderKey2 & SK2_USE_DEPTHFADETHRESHOLD) != 0)\n";
definesBlock << "#define NOT_ALPHATEST_ONLY ((uShaderKey2 & SK2_ALPHATEST_ONLY) == 0)\n";

View file

@ -105,7 +105,7 @@ public:
uint64_t LightMode : 2; // LIGHTMODE_DEFAULT, LIGHTMODE_SOFTWARE, LIGHTMODE_VANILLA, LIGHTMODE_BUILD
uint64_t LightBlendMode : 2; // LIGHT_BLEND_CLAMPED , LIGHT_BLEND_COLORED_CLAMP , LIGHT_BLEND_UNCLAMPED
uint64_t LightAttenuationMode : 1; // LIGHT_ATTENUATION_LINEAR , LIGHT_ATTENUATION_INVERSE_SQUARE
uint64_t Unused5: 1;
uint64_t PaletteMode: 1;
uint64_t FogBalls : 1; // FOGBALLS
uint64_t NoFragmentShader : 1;
uint64_t DepthFadeThreshold : 1;

View file

@ -62,17 +62,25 @@ void VkHardwareTexture::Reset()
}
mImage.Reset(fb);
mPaletteImage.Reset(fb);
mDepthStencil.Reset(fb);
}
}
VkTextureImage *VkHardwareTexture::GetImage(FTexture *tex, int translation, int flags)
{
if (!mImage.Image)
if (flags & (CTF_Indexed | CTF_IndexedRedIsAlpha))
{
CreateImage(tex, translation, flags);
if (!mPaletteImage.Image)
CreateImage(&mPaletteImage, tex, translation, flags);
return &mPaletteImage;
}
else
{
if (!mImage.Image)
CreateImage(&mImage, tex, translation, flags);
return &mImage;
}
return &mImage;
}
VkTextureImage *VkHardwareTexture::GetDepthStencil(FTexture *tex)
@ -105,7 +113,7 @@ VkTextureImage *VkHardwareTexture::GetDepthStencil(FTexture *tex)
return &mDepthStencil;
}
void VkHardwareTexture::CreateImage(FTexture *tex, int translation, int flags)
void VkHardwareTexture::CreateImage(VkTextureImage* image, FTexture *tex, int translation, int flags)
{
if (!tex->isHardwareCanvas())
{
@ -115,7 +123,7 @@ void VkHardwareTexture::CreateImage(FTexture *tex, int translation, int flags)
FTextureBuffer texbuffer = tex->CreateTexBuffer(translation, flags | CTF_CheckOnly);
bool indexed = flags & CTF_Indexed;
CreateTexture(texbuffer.mWidth, texbuffer.mHeight, indexed ? 1 : 4, indexed ? VK_FORMAT_R8_UNORM : VK_FORMAT_B8G8R8A8_UNORM, texbuffer.mBuffer, !indexed);
CreateTexture(image, texbuffer.mWidth, texbuffer.mHeight, indexed ? 1 : 4, indexed ? VK_FORMAT_R8_UNORM : VK_FORMAT_B8G8R8A8_UNORM, texbuffer.mBuffer, !indexed);
auto textureManager = fb->GetTextureManager();
@ -130,7 +138,7 @@ void VkHardwareTexture::CreateImage(FTexture *tex, int translation, int flags)
// Upload the texture on the main thread, as long as the hwrenderer didn't destroy this hwtexture already.
if (textureManager->CheckUploadID(uploadID))
{
UploadTexture(imagedata->mWidth, imagedata->mHeight, indexed ? 1 : 4, indexed ? VK_FORMAT_R8_UNORM : VK_FORMAT_B8G8R8A8_UNORM, imagedata->mBuffer, !indexed);
UploadTexture(image, imagedata->mWidth, imagedata->mHeight, indexed ? 1 : 4, indexed ? VK_FORMAT_R8_UNORM : VK_FORMAT_B8G8R8A8_UNORM, imagedata->mBuffer, !indexed);
}
});
@ -140,7 +148,7 @@ void VkHardwareTexture::CreateImage(FTexture *tex, int translation, int flags)
{
FTextureBuffer texbuffer = tex->CreateTexBuffer(translation, flags | CTF_ProcessData);
bool indexed = flags & CTF_Indexed;
CreateTexture(texbuffer.mWidth, texbuffer.mHeight, indexed ? 1 : 4, indexed ? VK_FORMAT_R8_UNORM : VK_FORMAT_B8G8R8A8_UNORM, texbuffer.mBuffer, !indexed);
CreateTexture(image, texbuffer.mWidth, texbuffer.mHeight, indexed ? 1 : 4, indexed ? VK_FORMAT_R8_UNORM : VK_FORMAT_B8G8R8A8_UNORM, texbuffer.mBuffer, !indexed);
}
}
else
@ -149,25 +157,25 @@ void VkHardwareTexture::CreateImage(FTexture *tex, int translation, int flags)
int w = tex->GetWidth();
int h = tex->GetHeight();
mImage.Image = ImageBuilder()
image->Image = ImageBuilder()
.Format(format)
.Size(w, h)
.Usage(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT)
.DebugName("VkHardwareTexture.mImage")
.Create(fb->GetDevice());
mImage.View = ImageViewBuilder()
.Image(mImage.Image.get(), format)
image->View = ImageViewBuilder()
.Image(image->Image.get(), format)
.DebugName("VkHardwareTexture.mImageView")
.Create(fb->GetDevice());
VkImageTransition()
.AddImage(&mImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, true)
.AddImage(image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, true)
.Execute(fb->GetCommands()->GetTransferCommands());
}
}
void VkHardwareTexture::CreateTexture(int w, int h, int pixelsize, VkFormat format, const void *pixels, bool mipmap)
void VkHardwareTexture::CreateTexture(VkTextureImage* image, int w, int h, int pixelsize, VkFormat format, const void *pixels, bool mipmap)
{
if (w <= 0 || h <= 0)
throw CVulkanError("Trying to create zero size texture");
@ -189,22 +197,22 @@ void VkHardwareTexture::CreateTexture(int w, int h, int pixelsize, VkFormat form
stagingBuffer->Unmap();
mImage.Image = ImageBuilder()
image->Image = ImageBuilder()
.Format(format)
.Size(w, h, !mipmap ? 1 : GetMipLevels(w, h))
.Usage(VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT)
.DebugName("VkHardwareTexture.mImage")
.Create(fb->GetDevice());
mImage.View = ImageViewBuilder()
.Image(mImage.Image.get(), format)
image->View = ImageViewBuilder()
.Image(image->Image.get(), format)
.DebugName("VkHardwareTexture.mImageView")
.Create(fb->GetDevice());
auto cmdbuffer = fb->GetCommands()->GetTransferCommands();
VkImageTransition()
.AddImage(&mImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true)
.AddImage(image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true)
.Execute(cmdbuffer);
VkBufferImageCopy region = {};
@ -213,9 +221,9 @@ void VkHardwareTexture::CreateTexture(int w, int h, int pixelsize, VkFormat form
region.imageExtent.depth = 1;
region.imageExtent.width = w;
region.imageExtent.height = h;
cmdbuffer->copyBufferToImage(stagingBuffer->buffer, mImage.Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
cmdbuffer->copyBufferToImage(stagingBuffer->buffer, image->Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
if (mipmap) mImage.GenerateMipmaps(cmdbuffer);
if (mipmap) image->GenerateMipmaps(cmdbuffer);
// If we queued more than 64 MB of data already: wait until the uploads finish before continuing
fb->GetCommands()->TransferDeleteList->Add(std::move(stagingBuffer));
@ -223,7 +231,7 @@ void VkHardwareTexture::CreateTexture(int w, int h, int pixelsize, VkFormat form
fb->GetCommands()->WaitForCommands(false, true);
}
void VkHardwareTexture::UploadTexture(int w, int h, int pixelsize, VkFormat format, const void* pixels, bool mipmap)
void VkHardwareTexture::UploadTexture(VkTextureImage* image, int w, int h, int pixelsize, VkFormat format, const void* pixels, bool mipmap)
{
if (w <= 0 || h <= 0)
throw CVulkanError("Trying to create zero size texture");
@ -243,7 +251,7 @@ void VkHardwareTexture::UploadTexture(int w, int h, int pixelsize, VkFormat form
auto cmdbuffer = fb->GetCommands()->GetTransferCommands();
VkImageTransition()
.AddImage(&mImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true)
.AddImage(image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true)
.Execute(cmdbuffer);
VkBufferImageCopy region = {};
@ -252,9 +260,9 @@ void VkHardwareTexture::UploadTexture(int w, int h, int pixelsize, VkFormat form
region.imageExtent.depth = 1;
region.imageExtent.width = w;
region.imageExtent.height = h;
cmdbuffer->copyBufferToImage(stagingBuffer->buffer, mImage.Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
cmdbuffer->copyBufferToImage(stagingBuffer->buffer, image->Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
if (mipmap) mImage.GenerateMipmaps(cmdbuffer);
if (mipmap) image->GenerateMipmaps(cmdbuffer);
// If we queued more than 64 MB of data already: wait until the uploads finish before continuing
fb->GetCommands()->TransferDeleteList->Add(std::move(stagingBuffer));
@ -323,7 +331,7 @@ unsigned int VkHardwareTexture::CreateTexture(unsigned char * buffer, int w, int
{
// CreateTexture is used by the software renderer to create a screen output but without any screen data.
if (buffer)
CreateTexture(w, h, mTexelsize, mTexelsize == 4 ? VK_FORMAT_B8G8R8A8_UNORM : VK_FORMAT_R8_UNORM, buffer, mipmap);
CreateTexture(&mImage, w, h, mTexelsize, mTexelsize == 4 ? VK_FORMAT_B8G8R8A8_UNORM : VK_FORMAT_R8_UNORM, buffer, mipmap);
return 0;
}
@ -409,9 +417,19 @@ VkMaterial::DescriptorEntry& VkMaterial::GetDescriptorEntry(const FMaterialState
clampmode = base->GetClampMode(clampmode);
int paletteFlags = 0;
if (state.mPaletteMode)
{
paletteFlags |= CTF_Indexed; // To do: may need to implement CTF_IndexedRedIsAlpha too for the "style.Flags & STYLEF_RedIsAlpha" case
// We can't do linear filtering for indexed textures
if (clampmode < CLAMP_NOFILTER)
clampmode += CLAMP_NOFILTER;
}
for (auto& set : mDescriptorSets)
{
if (set.clampmode == clampmode && set.remap == translationp && set.globalShaderAddr == globalShaderAddr) return set;
if (set.clampmode == clampmode && set.remap == translationp && set.globalShaderAddr == globalShaderAddr && set.indexed == state.mPaletteMode) return set;
}
auto globalshader = GetGlobalShader(globalShaderAddr);
@ -421,7 +439,7 @@ VkMaterial::DescriptorEntry& VkMaterial::GetDescriptorEntry(const FMaterialState
MaterialLayerInfo *layer;
auto systex = static_cast<VkHardwareTexture*>(GetLayer(0, state.mTranslation, &layer));
auto systeximage = systex->GetImage(layer->layerTexture, state.mTranslation, layer->scaleFlags);
auto systeximage = systex->GetImage(layer->layerTexture, state.mTranslation, layer->scaleFlags | paletteFlags);
int bindlessIndex = descriptors->AddBindlessTextureIndex(systeximage->View.get(), fb->GetSamplerManager()->Get(GetLayerFilter(0), clampmode));
if (!(layer->scaleFlags & CTF_Indexed))
@ -429,7 +447,7 @@ VkMaterial::DescriptorEntry& VkMaterial::GetDescriptorEntry(const FMaterialState
for (int i = 1; i < numLayersMat; i++)
{
auto syslayer = static_cast<VkHardwareTexture*>(GetLayer(i, 0, &layer));
auto syslayerimage = syslayer->GetImage(layer->layerTexture, 0, layer->scaleFlags);
auto syslayerimage = syslayer->GetImage(layer->layerTexture, 0, layer->scaleFlags | paletteFlags);
descriptors->AddBindlessTextureIndex(syslayerimage->View.get(), fb->GetSamplerManager()->Get(GetLayerFilter(i), clampmode));
}
@ -441,7 +459,7 @@ VkMaterial::DescriptorEntry& VkMaterial::GetDescriptorEntry(const FMaterialState
if (texture != nullptr)
{
VkHardwareTexture *tex = static_cast<VkHardwareTexture*>(texture.get()->GetHardwareTexture(0, 0));
VkTextureImage *img = tex->GetImage(texture.get(), 0, 0);
VkTextureImage *img = tex->GetImage(texture.get(), 0, paletteFlags);
descriptors->AddBindlessTextureIndex(img->View.get(), fb->GetSamplerManager()->Get(globalshader->CustomShaderTextureSampling[i], clampmode));
}
i++;
@ -453,11 +471,11 @@ VkMaterial::DescriptorEntry& VkMaterial::GetDescriptorEntry(const FMaterialState
for (int i = 1; i < 3; i++)
{
auto syslayer = static_cast<VkHardwareTexture*>(GetLayer(i, translation, &layer));
auto syslayerimage = syslayer->GetImage(layer->layerTexture, 0, layer->scaleFlags);
auto syslayerimage = syslayer->GetImage(layer->layerTexture, 0, layer->scaleFlags | paletteFlags);
descriptors->AddBindlessTextureIndex(syslayerimage->View.get(), fb->GetSamplerManager()->Get(GetLayerFilter(i), clampmode));
}
}
mDescriptorSets.emplace_back(clampmode, translationp, bindlessIndex, globalShaderAddr);
mDescriptorSets.emplace_back(clampmode, translationp, bindlessIndex, globalShaderAddr, state.mPaletteMode);
return mDescriptorSets.back();
}

View file

@ -46,13 +46,13 @@ public:
std::list<VkHardwareTexture*>::iterator it;
private:
void CreateImage(FTexture *tex, int translation, int flags);
void CreateImage(VkTextureImage* image, FTexture *tex, int translation, int flags);
void CreateTexture(int w, int h, int pixelsize, VkFormat format, const void *pixels, bool mipmap);
void UploadTexture(int w, int h, int pixelsize, VkFormat format, const void* pixels, bool mipmap);
void CreateTexture(VkTextureImage* image, int w, int h, int pixelsize, VkFormat format, const void *pixels, bool mipmap);
void UploadTexture(VkTextureImage* image, int w, int h, int pixelsize, VkFormat format, const void* pixels, bool mipmap);
static int GetMipLevels(int w, int h);
VkTextureImage mImage;
VkTextureImage mImage, mPaletteImage;
int mTexelsize = 4;
VkTextureImage mDepthStencil;
@ -80,13 +80,15 @@ private:
intptr_t remap;
int bindlessIndex;
GlobalShaderAddr globalShaderAddr;
bool indexed;
DescriptorEntry(int cm, intptr_t f, int index, GlobalShaderAddr addr)
DescriptorEntry(int cm, intptr_t f, int index, GlobalShaderAddr addr, bool paletteMode)
{
clampmode = cm;
remap = f;
bindlessIndex = index;
globalShaderAddr = addr;
indexed = paletteMode;
}
};

View file

@ -26,11 +26,13 @@
#include "vk_renderbuffers.h"
#include "vulkan/vk_postprocess.h"
#include "hw_cvars.h"
#include "fcolormap.h"
VkTextureManager::VkTextureManager(VulkanRenderDevice* fb) : fb(fb)
{
CreateNullTexture();
CreateBrdfLutTexture();
CreateGamePalette();
CreateShadowmap();
CreateLightmap();
CreateIrradiancemap();
@ -231,6 +233,113 @@ void VkTextureManager::CreateBrdfLutTexture()
.Execute(cmdbuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
}
void VkTextureManager::CreateGamePalette()
{
GamePalette = ImageBuilder()
.Format(VK_FORMAT_B8G8R8A8_UNORM)
.Size(256, 1)
.Usage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
.DebugName("VkDescriptorSetManager.GamePalette")
.Create(fb->GetDevice());
GamePaletteView = ImageViewBuilder()
.Image(GamePalette.get(), VK_FORMAT_B8G8R8A8_UNORM)
.DebugName("VkDescriptorSetManager.GamePaletteView")
.Create(fb->GetDevice());
}
void VkTextureManager::SetGamePalette()
{
auto cmdbuffer = fb->GetCommands()->GetTransferCommands();
PipelineBarrier()
.AddImage(GamePalette.get(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_ASPECT_COLOR_BIT)
.Execute(cmdbuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
auto stagingBuffer = BufferBuilder()
.Size(256 * 4)
.Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY)
.DebugName("VkDescriptorSetManager.GamePaletteStagingBuffer")
.Create(fb->GetDevice());
void* data = stagingBuffer->Map(0, 256 * 4);
memcpy(data, GPalette.BaseColors, 256 * 4);
stagingBuffer->Unmap();
VkBufferImageCopy region = {};
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.imageSubresource.layerCount = 1;
region.imageExtent.depth = 1;
region.imageExtent.width = 256;
region.imageExtent.height = 1;
cmdbuffer->copyBufferToImage(stagingBuffer->buffer, GamePalette->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
fb->GetCommands()->TransferDeleteList->Add(std::move(stagingBuffer));
PipelineBarrier()
.AddImage(GamePalette.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT)
.Execute(cmdbuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
}
VulkanImageView* VkTextureManager::GetSWColormapView(FSWColormap* colormap)
{
if (colormap->Renderdev.textureIndex != -1)
return Colormaps[colormap->Renderdev.textureIndex].View.get();
SWColormapTexture tex;
tex.Texture = ImageBuilder()
.Format(VK_FORMAT_B8G8R8A8_UNORM)
.Size(256, 32)
.Usage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
.DebugName("VkDescriptorSetManager.SWColormap")
.Create(fb->GetDevice());
tex.View = ImageViewBuilder()
.Image(tex.Texture.get(), VK_FORMAT_B8G8R8A8_UNORM)
.DebugName("VkDescriptorSetManager.SWColormapView")
.Create(fb->GetDevice());
auto cmdbuffer = fb->GetCommands()->GetTransferCommands();
PipelineBarrier()
.AddImage(tex.Texture.get(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, VK_ACCESS_TRANSFER_WRITE_BIT, VK_IMAGE_ASPECT_COLOR_BIT)
.Execute(cmdbuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
auto stagingBuffer = BufferBuilder()
.Size(256 * 32 * sizeof(uint32_t))
.Usage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY)
.DebugName("VkDescriptorSetManager.SWColormapStagingBuffer")
.Create(fb->GetDevice());
const uint8_t* src = colormap->Maps;
uint32_t* data = static_cast<uint32_t*>(stagingBuffer->Map(0, 256 * 32 * sizeof(uint32_t)));
for (int i = 0; i < 256 * 32; i++)
{
data[i] = GPalette.BaseColors[src[i]].d;
}
stagingBuffer->Unmap();
VkBufferImageCopy region = {};
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
region.imageSubresource.layerCount = 1;
region.imageExtent.depth = 1;
region.imageExtent.width = 256;
region.imageExtent.height = 32;
cmdbuffer->copyBufferToImage(stagingBuffer->buffer, tex.Texture->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
fb->GetCommands()->TransferDeleteList->Add(std::move(stagingBuffer));
PipelineBarrier()
.AddImage(tex.Texture.get(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT)
.Execute(cmdbuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
colormap->Renderdev.textureIndex = Colormaps.size();
Colormaps.push_back(std::move(tex));
return Colormaps[colormap->Renderdev.textureIndex].View.get();
}
void VkTextureManager::CreateShadowmap()
{
Shadowmap.Image = ImageBuilder()

View file

@ -16,6 +16,7 @@ class VkPPTexture;
class VkTextureImage;
enum class PPTextureType;
class PPTexture;
struct FSWColormap;
class VkTextureManager
{
@ -32,6 +33,8 @@ public:
void CreatePrefiltermap(int size, int count, const TArray<uint16_t>& data);
void DownloadLightmap(int arrayIndex, uint16_t* buffer);
void SetGamePalette();
VkTextureImage* GetTexture(const PPTextureType& type, PPTexture* tex);
VkFormat GetTextureFormat(PPTexture* texture);
@ -47,6 +50,11 @@ public:
VulkanImage* GetBrdfLutTexture() { return BrdfLutTexture.get(); }
VulkanImageView* GetBrdfLutTextureView() { return BrdfLutTextureView.get(); }
VulkanImage* GetGamePalette() { return GamePalette.get(); }
VulkanImageView* GetGamePaletteView() { return GamePaletteView.get(); }
VulkanImageView* GetSWColormapView(FSWColormap* colormap);
int GetHWTextureCount() { return (int)Textures.size(); }
VkTextureImage Shadowmap;
@ -70,6 +78,7 @@ public:
private:
void CreateNullTexture();
void CreateBrdfLutTexture();
void CreateGamePalette();
void CreateShadowmap();
void CreateLightmap();
void CreateIrradiancemap();
@ -92,6 +101,16 @@ private:
std::unique_ptr<VulkanImage> BrdfLutTexture;
std::unique_ptr<VulkanImageView> BrdfLutTextureView;
std::unique_ptr<VulkanImage> GamePalette;
std::unique_ptr<VulkanImageView> GamePaletteView;
struct SWColormapTexture
{
std::unique_ptr<VulkanImage> Texture;
std::unique_ptr<VulkanImageView> View;
};
std::vector<SWColormapTexture> Colormaps;
int NextUploadID = 1;
std::unordered_map<int, VkHardwareTexture*> PendingUploads;

View file

@ -844,7 +844,7 @@ void VkLevelMeshUploader::UploadSurfaces()
if (surface->Texture)
{
auto mat = FMaterial::ValidateTexture(surface->Texture, 0);
info.TextureIndex = Mesh->fb->GetBindlessTextureIndex(mat, CLAMP_NONE, 0);
info.TextureIndex = Mesh->fb->GetBindlessTextureIndex(mat, CLAMP_NONE, 0, false);
}
else
{
@ -873,7 +873,7 @@ void VkLevelMeshUploader::UploadUniforms()
auto source = material.mMaterial->Source();
surfaceUniforms.uSpecularMaterial = { source->GetGlossiness(), source->GetSpecularLevel() };
surfaceUniforms.uDepthFadeThreshold = source->GetDepthFadeThreshold();
surfaceUniforms.uTextureIndex = Mesh->fb->GetBindlessTextureIndex(material.mMaterial, material.mClampMode, material.mTranslation);
surfaceUniforms.uTextureIndex = Mesh->fb->GetBindlessTextureIndex(material.mMaterial, material.mClampMode, material.mTranslation, false);
}
else
{

View file

@ -482,6 +482,8 @@ void VulkanRenderDevice::UpdatePalette()
{
if (mPostprocess)
mPostprocess->ClearTonemapPalette();
mTextureManager->SetGamePalette();
}
FTexture *VulkanRenderDevice::WipeStartScreen()
@ -748,7 +750,7 @@ void VulkanRenderDevice::DownloadLightmap(int arrayIndex, uint16_t* buffer)
mTextureManager->DownloadLightmap(arrayIndex, buffer);
}
int VulkanRenderDevice::GetBindlessTextureIndex(FMaterial* material, int clampmode, int translation)
int VulkanRenderDevice::GetBindlessTextureIndex(FMaterial* material, int clampmode, int translation, bool paletteMode)
{
GlobalShaderAddr addr;
auto globalshader = GetGlobalShader(material->GetShaderIndex(), nullptr, addr);
@ -757,6 +759,7 @@ int VulkanRenderDevice::GetBindlessTextureIndex(FMaterial* material, int clampmo
materialState.mMaterial = material;
materialState.mClampMode = clampmode;
materialState.mTranslation = translation;
materialState.mPaletteMode = paletteMode;
if(addr.type == 1 && *globalshader)
{ // handle per-map global shaders

View file

@ -95,7 +95,7 @@ public:
void WaitForCommands(bool finish) override;
int GetBindlessTextureIndex(FMaterial* material, int clampmode, int translation) override;
int GetBindlessTextureIndex(FMaterial* material, int clampmode, int translation, bool paletteMode) override;
int GetLevelMeshPipelineID(const MeshApplyData& applyData, const SurfaceUniforms& surfaceUniforms, const FMaterialState& material) override;
void DownloadLightmap(int arrayIndex, uint16_t* buffer) override;

View file

@ -343,6 +343,8 @@ void VkRenderState::ApplyRenderPass(int dt)
pipelineKey.ShaderKey.LightBlendMode = (level.info ? static_cast<int>(level.info->lightblendmode) : 0);
pipelineKey.ShaderKey.LightAttenuationMode = (level.info ? static_cast<int>(level.info->lightattenuationmode) : 0);
pipelineKey.ShaderKey.PaletteMode = mPaletteMode;
// Is this the one we already have?
bool inRenderPass = mCommandBuffer;
bool changingPipeline = (!inRenderPass) || (pipelineKey != mPipelineKey);
@ -441,6 +443,21 @@ void VkRenderState::ApplySurfaceUniforms()
else
mSurfaceUniforms.timer = 0.0f;
if (mMaterial.mPaletteMode != mPaletteMode)
{
mMaterial.mPaletteMode = mPaletteMode;
mMaterial.mChanged = true;
}
if (mPaletteMode && mSWColormap)
{
mSurfaceUniforms.uColormapIndex = fb->GetDescriptorSetManager()->GetSWColormapTextureIndex(mSWColormap);
}
else
{
mSurfaceUniforms.uColormapIndex = 0;
}
if (mMaterial.mChanged)
{
if (mMaterial.mMaterial)

View file

@ -15,6 +15,7 @@ enum ECreateTexBufferFlags
CTF_Indexed = 4, // Tell the backend to create an indexed texture.
CTF_CheckOnly = 8, // Only runs the code to get a content ID but does not create a texture. Can be used to access a caching system for the hardware textures.
CTF_ProcessData = 16, // run postprocessing on the generated buffer. This is only needed when using the data for a hardware texture.
CTF_IndexedRedIsAlpha = 32, // Tell the backend to create an indexed alpha texture.
};
class FHardwareTextureContainer

View file

@ -332,12 +332,13 @@ FTextureBuffer FTexture::CreateTexBuffer(int translation, int flags)
std::unique_lock lock(mutex);
FTextureBuffer result;
if (flags & CTF_Indexed)
if (flags & (CTF_Indexed | CTF_IndexedRedIsAlpha))
{
// Indexed textures will never be translated and never be scaled.
int w = GetWidth(), h = GetHeight();
auto store = Get8BitPixels(false);
bool alpha = !!(flags & CTF_IndexedRedIsAlpha);
auto store = Get8BitPixels(alpha);
const uint8_t* p = store.Data();
result.mBuffer = new uint8_t[w * h];

View file

@ -241,9 +241,9 @@ CUSTOM_CVAR(Int, vid_rendermode, 4, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOIN
{
self = 4;
}
else if (self == 2 || self == 3)
else if (self == 3)
{
self = self - 2; // softpoly to software
self = 4; // map old softpoly truecolor to hwrenderer
}
if (usergame)
@ -405,7 +405,7 @@ void D_Render(std::function<void()> action, bool interpolate)
for (auto Level : AllLevels())
{
// Check for the presence of dynamic lights at the start of the frame once.
if ((gl_lights && vid_rendermode == 4) || (r_dynlights && vid_rendermode != 4) || Level->lightmaps)
if ((gl_lights && V_IsHardwareRenderer()) || (r_dynlights && V_IsSoftwareRenderer()) || Level->lightmaps)
{
Level->HasDynamicLights = Level->lights || Level->lightmaps;
}
@ -987,7 +987,7 @@ void D_Display ()
// No wipes when in a stereo3D VR mode
else if (gamestate != wipegamestate && gamestate != GS_FULLCONSOLE && gamestate != GS_TITLELEVEL)
{
if (vr_mode == 0 || vid_rendermode != 4)
if (vr_mode == 0 || V_IsSoftwareRenderer())
{
// save the current screen if about to wipe
wipestart = screen->WipeStartScreen();
@ -3320,11 +3320,8 @@ static int D_InitGame(const FIWADInfo* iwad_info, std::vector<std::string>& allw
screen->CompileNextShader();
if (StartScreen != nullptr) StartScreen->Render();
}
else
{
// Update screen palette when restarting
screen->UpdatePalette();
}
screen->UpdatePalette();
// Base systems have been inited; enable cvar callbacks
FBaseCVar::EnableCallbacks ();

View file

@ -161,7 +161,12 @@ constexpr int vid_rendermode = 4;
inline bool V_IsHardwareRenderer()
{
return vid_rendermode == 4;
return vid_rendermode == 4 || vid_rendermode == 2;
}
inline bool V_IsSoftwareRenderer()
{
return !V_IsHardwareRenderer();
}
inline bool V_IsTrueColor()

View file

@ -111,7 +111,7 @@ void FThinkerCollection::RunThinkers(FLevelLocals *Level)
ThinkCycles.Clock();
bool dolights;
if ((gl_lights && vid_rendermode == 4) || (r_dynlights && vid_rendermode != 4) || Level->lightmaps)
if ((gl_lights && V_IsHardwareRenderer()) || (r_dynlights && V_IsSoftwareRenderer()) || Level->lightmaps)
{
dolights = true;// Level->lights || (Level->flags3 & LEVEL3_LIGHTCREATED) || Level->lightmaps;
}

View file

@ -48,6 +48,8 @@
#include "actorinlines.h"
#include "g_levellocals.h"
#include "hw_lighting.h"
#include "d_main.h"
#include "swrenderer/r_swcolormaps.h"
EXTERN_CVAR(Float, r_visibility)
EXTERN_CVAR(Int, lm_background_updates);
@ -783,6 +785,15 @@ void HWDrawInfo::RenderScene(FRenderState &state)
UpdateLightmaps();
state.SetLightMode((int)lightmode);
if (!V_IsTrueColor())
{
state.SetPaletteMode(!V_IsTrueColor());
FColormap cm;
cm.Clear();
state.SetSWColormap(GetColorTable(cm));
}
state.SetDepthMask(true);
@ -829,6 +840,8 @@ void HWDrawInfo::RenderScene(FRenderState &state)
state.SetDepthFunc(DF_LEqual);
DrawDecals(state, Decals[0]);
state.SetPaletteMode(false);
RenderAll.Unclock();
}

View file

@ -3,14 +3,6 @@
#include "g_levellocals.h"
struct FSWColormap
{
uint8_t *Maps = nullptr;
PalEntry Color = 0xffffffff;
PalEntry Fade = 0xff000000;
int Desaturate = 0;
};
struct FDynamicColormap : FSWColormap
{
void ChangeFade (PalEntry fadecolor);

View file

@ -114,10 +114,10 @@ struct SurfaceUniforms
float uAlphaThreshold;
int uTextureIndex;
float uDepthFadeThreshold;
int uColormapIndex;
int uLightProbeIndex;
vec3 uActorCenter;
float padding2;
float uDepthFadeThreshold;
};
struct SurfaceLightUniforms

View file

@ -55,6 +55,7 @@
#define uLightDist data[uDataIndex].uLightDist
#define uAlphaThreshold data[uDataIndex].uAlphaThreshold
#define uTextureIndex data[uDataIndex].uTextureIndex
#define uColormapIndex data[uDataIndex].uColormapIndex
#define uDepthFadeThreshold data[uDataIndex].uDepthFadeThreshold
#define uActorCenter data[uDataIndex].uActorCenter
#define uLightProbeIndex data[uDataIndex].uLightProbeIndex

View file

@ -22,75 +22,96 @@
vec4 getLightColor(Material material)
{
vec4 color;
if (LIGHTMODE_DEFAULT)
color = Lightmode_Default();
else if (LIGHTMODE_SOFTWARE)
color = Lightmode_Software();
else if (LIGHTMODE_VANILLA)
color = Lightmode_Vanilla();
else if (LIGHTMODE_BUILD)
color = Lightmode_Build();
//
// handle glowing walls
//
if (uGlowTopColor.a > 0.0 && glowdist.x < uGlowTopColor.a)
if (PALETTEMODE)
{
color.rgb += desaturate(uGlowTopColor * (1.0 - glowdist.x / uGlowTopColor.a)).rgb;
}
if (uGlowBottomColor.a > 0.0 && glowdist.y < uGlowBottomColor.a)
{
color.rgb += desaturate(uGlowBottomColor * (1.0 - glowdist.y / uGlowBottomColor.a)).rgb;
}
color = min(color, 1.0);
int color = int(material.Base.r * 255.0 + 0.5);
// these cannot be safely applied by the legacy format where the implementation cannot guarantee that the values are set.
#if !defined LEGACY_USER_SHADER && !defined NO_LAYERS
//
// apply glow
//
color.rgb = mix(color.rgb, material.Glow.rgb, material.Glow.a);
//
// apply brightmaps
//
color.rgb = min(color.rgb + material.Bright.rgb, 1.0);
#endif
//
// apply lightmaps
//
if (vLightmap.z >= 0.0)
{
color.rgb += texture(LightMap, vLightmap).rgb;
}
//
// apply dynamic lights
//
vec4 frag = vec4(ProcessMaterialLight(material, color.rgb), material.Base.a * vColor.a);
//
// colored fog
//
if (FOG_AFTER_LIGHTS)
{
// calculate fog factor
float fogdist;
if (FOG_RADIAL)
fogdist = max(16.0, distance(pixelpos.xyz, uCameraPos.xyz));
// z is the depth in view space, positive going into the screen
float z;
if (SWLIGHT_RADIAL)
z = distance(pixelpos.xyz, uCameraPos.xyz);
else
fogdist = max(16.0, pixelpos.w);
float fogfactor = exp2 (uFogDensity * fogdist);
z = pixelpos.w;
frag = vec4(mix(uFogColor.rgb, frag.rgb, fogfactor), frag.a);
float L = uLightLevel * 255.0;
float vis = min(uGlobVis / z, 24.0 / 32.0);
float shade = 2.0 - (L + 12.0) / 128.0;
int light = max(int((shade - vis) * 32), 0);
return vec4(texelFetch(textures[uColormapIndex], ivec2(color, light), 0).rgb, 1.0);
}
else
{
vec4 color;
if (LIGHTMODE_DEFAULT)
color = Lightmode_Default();
else if (LIGHTMODE_SOFTWARE)
color = Lightmode_Software();
else if (LIGHTMODE_VANILLA)
color = Lightmode_Vanilla();
else if (LIGHTMODE_BUILD)
color = Lightmode_Build();
if (FOGBALLS)
frag = ProcessFogBalls(frag);
//
// handle glowing walls
//
if (uGlowTopColor.a > 0.0 && glowdist.x < uGlowTopColor.a)
{
color.rgb += desaturate(uGlowTopColor * (1.0 - glowdist.x / uGlowTopColor.a)).rgb;
}
if (uGlowBottomColor.a > 0.0 && glowdist.y < uGlowBottomColor.a)
{
color.rgb += desaturate(uGlowBottomColor * (1.0 - glowdist.y / uGlowBottomColor.a)).rgb;
}
color = min(color, 1.0);
return frag;
// these cannot be safely applied by the legacy format where the implementation cannot guarantee that the values are set.
#if !defined LEGACY_USER_SHADER && !defined NO_LAYERS
//
// apply glow
//
color.rgb = mix(color.rgb, material.Glow.rgb, material.Glow.a);
//
// apply brightmaps
//
color.rgb = min(color.rgb + material.Bright.rgb, 1.0);
#endif
//
// apply lightmaps
//
if (vLightmap.z >= 0.0)
{
color.rgb += texture(LightMap, vLightmap).rgb;
}
//
// apply dynamic lights
//
vec4 frag = vec4(ProcessMaterialLight(material, color.rgb), material.Base.a * vColor.a);
//
// colored fog
//
if (FOG_AFTER_LIGHTS)
{
// calculate fog factor
float fogdist;
if (FOG_RADIAL)
fogdist = max(16.0, distance(pixelpos.xyz, uCameraPos.xyz));
else
fogdist = max(16.0, pixelpos.w);
float fogfactor = exp2 (uFogDensity * fogdist);
frag = vec4(mix(uFogColor.rgb, frag.rgb, fogfactor), frag.a);
}
if (FOGBALLS)
frag = ProcessFogBalls(frag);
return frag;
}
}
// The color of the fragment if it is fully occluded by ambient lighting

View file

@ -37,7 +37,7 @@
#define SK1_LIGHT_LIGHT_BLEND_COLORED_CLAMP 1
#define SK1_LIGHT_BLEND_UNCLAMPED 2
#define SK1_LIGHTATTENUATIONMODE (1 << 29)
//#define SK1_USE_LEVELMESH (1 << 30)
#define SK1_PALETTEMODE (1 << 30)
#define SK1_FOGBALLS (1 << 31)
//#define SK2_NOFRAGMENTSHADER (1 << 0)