Skip to content

Commit

Permalink
sokol: WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
IonAgorria committed Oct 20, 2024
1 parent 7dd716e commit ede8b7c
Show file tree
Hide file tree
Showing 10 changed files with 297 additions and 183 deletions.
1 change: 1 addition & 0 deletions Source/Render/inc/StdAfxRD.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <list>
#include <stack>
#include <map>
#include <unordered_set>
#include <unordered_map>

#if (!defined(_FINAL_VERSION_) || defined(_DEBUG)) && !defined(NASSERT)
Expand Down
146 changes: 87 additions & 59 deletions Source/Render/sokol/SokolRender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ int cSokolRender::Init(int xScr, int yScr, int mode, SDL_Window* wnd, int Refres
}

ClearPooledResources(0);
ClearCommands();
ClearAllCommands();
ClearPipelines();

const char* sokol_backend = "Unknown";
Expand Down Expand Up @@ -302,6 +302,7 @@ int cSokolRender::Init(int xScr, int yScr, int mode, SDL_Window* wnd, int Refres
#ifdef PERIMETER_DEBUG
emptyTexture->label = "EmptySlotTexture";
#endif
PrepareSokolTexture(emptyTexture);

for (int i = 0; i < PERIMETER_SOKOL_TEXTURES; ++i) {
activeTextureTransform[i] = Mat4f::ID;
Expand Down Expand Up @@ -364,7 +365,7 @@ int cSokolRender::Done() {
int ret = cInterfaceRenderDevice::Done();
activeCommand.Clear();
ClearPooledResources(0);
ClearCommands();
ClearAllCommands();
ClearPipelines();
shaders.clear();
delete emptyTexture;
Expand Down Expand Up @@ -429,74 +430,101 @@ void cSokolRender::DeleteIndexBuffer(IndexBuffer &ib) {

#define ClearPooledResources_Debug 0
void cSokolRender::ClearPooledResources(uint32_t max_life) {
if (bufferPool.empty()) {
if (bufferPool.empty() && imagePool.empty()) {
return;
}
#if defined(PERIMETER_DEBUG) && ClearPooledResources_Debug
size_t count = bufferPool.size();
size_t bufferCount = bufferPool.size();
size_t imageCount = imagePool.size();
#endif
auto it = bufferPool.begin();
while (it != bufferPool.end()) {
auto& res = it->second;
res.unused_since++;
if (res.unused_since >= max_life) {
res.resource->DecRef();
res.resource = nullptr;
it = bufferPool.erase(it);
} else {
it++;
{
auto it = bufferPool.begin();
while (it != bufferPool.end()) {
auto& res = it->second;
res.unused_since++;
if (res.unused_since >= max_life) {
res.resource->DecRef();
res.resource = nullptr;
it = bufferPool.erase(it);
} else {
it++;
}
}
}
{
auto it = imagePool.begin();
while (it != imagePool.end()) {
auto& res = it->second;
res.unused_since++;
if (res.unused_since >= max_life) {
res.resource->DecRef();
res.resource = nullptr;
it = imagePool.erase(it);
} else {
it++;
}
}
}
#if defined(PERIMETER_DEBUG) && ClearPooledResources_Debug
if (count != bufferPool.size()) {
printf("ClearPooledResources %" PRIsize " -> %" PRIsize "\n", count, bufferPool.size());
if (bufferCount != bufferPool.size()) {
printf("ClearPooledResources buffers %" PRIsize " -> %" PRIsize "\n", bufferCount, bufferPool.size());
}
if (imageCount != imagePool.size()) {
printf("ClearPooledResources images %" PRIsize " -> %" PRIsize "\n", imageCount, imagePool.size());
}
#endif
}

void cSokolRender::ClearCommands() {
std::unordered_set<SokolResourceBuffer*> pooled;
auto ClearCommands = [&pooled, this](std::vector<SokolCommand*>& commands) {
for (SokolCommand* command : commands) {
//Reclaim resources that can be reused
SokolResourceBuffer* vertex_buffer = command->vertex_buffer;
if (vertex_buffer && vertex_buffer->key != SokolResourceKeyNone && pooled.count(vertex_buffer) == 0) {
command->vertex_buffer = nullptr;
xassert(0 < vertex_buffer->RefCount() && vertex_buffer->RefCount() <= 50);
bufferPool.emplace(
vertex_buffer->key,
SokolResourcePooled(vertex_buffer)
);
pooled.emplace(vertex_buffer);
}
SokolResourceBuffer* index_buffer = command->index_buffer;
if (index_buffer && index_buffer->key != SokolResourceKeyNone && pooled.count(index_buffer) == 0) {
command->index_buffer = nullptr;
xassert(0 < index_buffer->RefCount() && index_buffer->RefCount() <= 50);
bufferPool.emplace(
index_buffer->key,
SokolResourcePooled(index_buffer)
);
pooled.emplace(index_buffer);
#define CanStorePooledResource(res) (res && !res->pooled && res->key != SokolResourceKeyNone)

template<typename T>
void StorePooledResource(
std::unordered_multimap<uint64_t, SokolResourcePooled<T>>& res_pool,
SokolResource<T>*& res
) {
xassert(CanStorePooledResource(res));
xassert(0 < res->RefCount() && res->RefCount() <= 10000);
res->IncRef();
res->pooled = true;
res->burned = false;
res_pool.emplace(
res->key,
SokolResourcePooled<T>(res)
);
}

void cSokolRender::ClearCommands(std::vector<SokolCommand*>& commands_to_clear) {
for (SokolCommand* command : commands_to_clear) {
//Reclaim resources that can be reused
if (CanStorePooledResource(command->vertex_buffer)) {
StorePooledResource(bufferPool, command->vertex_buffer);
}
if (CanStorePooledResource(command->index_buffer)) {
StorePooledResource(bufferPool, command->index_buffer);
}
for (SokolResourceImage* image : command->sokol_images) {
if (CanStorePooledResource(image)) {
StorePooledResource(imagePool, image);
}

delete command;
}
};

for (auto& target : std::array<SokolRenderTarget*, 2>{shadowMapRenderTarget, lightMapRenderTarget}) {
delete command;
}

commands_to_clear.clear();
}

void cSokolRender::ClearAllCommands() {
for (auto& target : {
shadowMapRenderTarget,
lightMapRenderTarget
}) {
if (target != nullptr) {
ClearCommands(target->commands);
target->commands.clear();
}
}

ClearCommands(commands);
commands.clear();

#ifdef PERIMETER_DEBUG
//printf("%ld %ld\n", reclaimed.size(), bufferPool.size());
#endif
}

void cSokolRender::ClearPipelines() {
Expand Down Expand Up @@ -712,25 +740,25 @@ void SokolCommand::ClearShaderParams() {
fs_params_len = 0;
}

void SokolCommand::ClearTextures() {
void SokolCommand::ClearImages() {
for (int i = 0; i < PERIMETER_SOKOL_TEXTURES; ++i) {
SetTexture(i, nullptr);
SetImage(i, nullptr);
}
}

void SokolCommand::Clear() {
ClearDrawData();
ClearShaderParams();
ClearTextures();
ClearImages();
}

void SokolCommand::SetTexture(size_t index, SokolResourceTexture* texture) {
void SokolCommand::SetImage(size_t index, SokolResourceImage* image) {
xassert(index<PERIMETER_SOKOL_TEXTURES);
if (texture) {
texture->IncRef();
if (image) {
image->IncRef();
}
if (sokol_textures[index]) {
sokol_textures[index]->DecRef();
if (sokol_images[index]) {
sokol_images[index]->DecRef();
}
sokol_textures[index] = texture;
sokol_images[index] = image;
}
22 changes: 13 additions & 9 deletions Source/Render/sokol/SokolRender.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,12 @@
#define PERIMETER_SOKOL_GL (1)
#endif

#include <tuple>

#include <sokol_gfx.h>
#include <SDL_video.h>

#include "SokolTypes.h"

const int PERIMETER_SOKOL_TEXTURES = 8;
const int PERIMETER_SOKOL_TEXTURES = 4;

struct SokolCommand {
SokolCommand();
Expand All @@ -21,16 +19,16 @@ struct SokolCommand {
void Clear();
void ClearDrawData();
void ClearShaderParams();
void SetTexture(size_t index, SokolResource<sg_image>* sokol_texture);
void ClearTextures();
void SetImage(size_t index, SokolResourceImage* image);
void ClearImages();
NO_COPY_CONSTRUCTOR(SokolCommand);

struct SokolPipeline* pipeline = nullptr;
sg_pass_action* pass_action = nullptr;
size_t base_elements = 0;
size_t vertices = 0;
size_t indices = 0;
SokolResourceTexture* sokol_textures[PERIMETER_SOKOL_TEXTURES] = {};
SokolResourceImage* sokol_images[PERIMETER_SOKOL_TEXTURES] = {};
SokolResourceBuffer* vertex_buffer = nullptr;
SokolResourceBuffer* index_buffer = nullptr;
void* vs_params = nullptr;
Expand Down Expand Up @@ -98,6 +96,7 @@ class cSokolRender: public cInterfaceRenderDevice {
//Stores resources for reusing
void ClearPooledResources(uint32_t max_life);
std::unordered_multimap<uint64_t, SokolResourcePooled<sg_buffer>> bufferPool;
std::unordered_multimap<uint64_t, SokolResourcePooled<sg_image>> imagePool;

//For swapchain pass that renders into final device
sg_swapchain swapchain = {};
Expand Down Expand Up @@ -133,8 +132,9 @@ class cSokolRender: public cInterfaceRenderDevice {

//Active pipeline/command state
SokolCommand activeCommand;
SokolTexture2D* activeCommandTextures[PERIMETER_SOKOL_TEXTURES] = {};
PIPELINE_TYPE activePipelineType = PIPELINE_TYPE_DEFAULT;
PIPELINE_MODE activePipelineMode;
SokolPipelineMode activePipelineMode;
Mat4f activeCommandVP;
Mat4f activeCommandW;
eColorMode activeCommandColorMode = COLOR_MOD;
Expand All @@ -161,7 +161,8 @@ class cSokolRender: public cInterfaceRenderDevice {

//Commands handling
void ClearActiveBufferAndPassAction();
void ClearCommands();
void ClearCommands(std::vector<SokolCommand*>& commands);
void ClearAllCommands();
void FinishActiveDrawBuffer();
void CreateCommandEmpty();
void CreateCommand(class VertexBuffer* vb, size_t vertices, class IndexBuffer* ib, size_t indices);
Expand All @@ -173,13 +174,16 @@ class cSokolRender: public cInterfaceRenderDevice {

///Assigns unused sokol buffer to buffer_ptr with requested
void PrepareSokolBuffer(SokolBuffer*& buffer_ptr, MemoryResource* resource, size_t len, bool dynamic, sg_buffer_type type);

///Prepares internal sokol image
void PrepareSokolTexture(SokolTexture2D* tex);

//Updates internal state after init/resolution change
int UpdateRenderMode();

//Does actual drawing using sokol API
void DoSokolRendering();
void DoSokolRendering(sg_pass& render_pass, const std::vector<SokolCommand*>& commands);
void ProcessRenderPass(sg_pass& render_pass, const std::vector<SokolCommand*>& commands);

//Set common VS/FS parameters
template<typename T_VS, typename T_FS>
Expand Down
23 changes: 5 additions & 18 deletions Source/Render/sokol/SokolRenderDraw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,8 @@ void cSokolRender::SetMaterialTilemap(cTileMap *TileMap) {
Mat4f matlight = pShadow->matViewProj;
activeShadowMatrix = matlight * matTexAdj;

activeCommand.SetTexture(0, pShadowMap->GetFrameImage(0)->sg->image);
activeCommand.SetTexture(2, pLightMap->GetFrameImage(0)->sg->image);
SetTextureImage(0, pShadowMap->GetFrameImage(0));
SetTextureImage(2, pLightMap->GetFrameImage(0));

TerraInterface* terra = TileMap->GetTerra();
activeWorldSize = Vect2f(1.0f / terra->SizeX(), 1.0f / terra->SizeY());
Expand Down Expand Up @@ -270,25 +270,13 @@ void cSokolRender::SetTileColor(sColor4f color) {
bool cSokolRender::CreateShadowTexture(int xysize) {
DeleteShadowTexture();

auto SetupTexture = [](SokolTexture2D *texture, sg_pixel_format pixel_format) {
auto description = texture->desc;
description->render_target = true;
description->usage = SG_USAGE_IMMUTABLE;
description->pixel_format = pixel_format;
SokolResourceKey resource_key = get_sokol_resource_key_texture(
description->width, description->height, description->pixel_format);
texture->image = new SokolResourceTexture(resource_key, sg_make_image(description));
texture->resource_key = texture->image->key;
texture->dirty = false;
};

shadowMapRenderTarget = new SokolRenderTarget{};
shadowMapRenderTarget->texture = GetTexLibrary()->CreateRenderTexture(xysize, xysize, TEXTURE_RENDER16, false);
shadowMapRenderTarget->texture = GetTexLibrary()->CreateRenderTexture(xysize, xysize, TEXTURE_RENDER_DEPTH, false);
if (!shadowMapRenderTarget->texture) {
DeleteShadowTexture();
return false;
}
SetupTexture(shadowMapRenderTarget->texture->GetFrameImage(0)->sg, SG_PIXELFORMAT_DEPTH);
PrepareSokolTexture(shadowMapRenderTarget->texture->GetFrameImage(0)->sg);

{
auto& render_pass = shadowMapRenderTarget->render_pass;
Expand All @@ -307,8 +295,7 @@ bool cSokolRender::CreateShadowTexture(int xysize) {
DeleteShadowTexture();
return false;
}
SetupTexture(lightMapRenderTarget->texture->GetFrameImage(0)->sg,
sg_query_desc().environment.defaults.color_format);
PrepareSokolTexture(lightMapRenderTarget->texture->GetFrameImage(0)->sg);

{
auto& render_pass = lightMapRenderTarget->render_pass;
Expand Down
Loading

0 comments on commit ede8b7c

Please sign in to comment.