Skip to content

Commit

Permalink
Hook webgl context events.
Browse files Browse the repository at this point in the history
Implement rendering pause.
Add missing implementation.
  • Loading branch information
ekharkunov committed May 11, 2024
1 parent 9c13c5f commit ba9c476
Show file tree
Hide file tree
Showing 11 changed files with 190 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -842,6 +842,13 @@ var Module = {
if (Module.hasWebGLSupport()) {
Module.canvas.focus();

Module.canvas.addEventListener("webglcontextlost", function(event) {
event.preventDefault();
dmRenderer.rendererContextEvent("context_lost");
}, false);
Module.canvas.addEventListener("webglcontextrestored", function(event) {
dmRenderer.rendererContextEvent("context_restored");
}, false);
// Add context menu hide-handler if requested
if (CUSTOM_PARAMETERS["disable_context_menu"])
{
Expand Down
3 changes: 2 additions & 1 deletion engine/engine/src/engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1652,7 +1652,8 @@ namespace dmEngine
dmGameObject::Update(engine->m_MainCollection, &update_context);

// Don't render while iconified
if (!dmGraphics::GetWindowStateParam(engine->m_GraphicsContext, dmPlatform::WINDOW_STATE_ICONIFIED))
if (!dmGraphics::GetWindowStateParam(engine->m_GraphicsContext, dmPlatform::WINDOW_STATE_ICONIFIED)
&& !dmRender::IsRenderPaused(engine->m_RenderContext))
{
// Call pre render functions for extensions, if available.
// We do it here before we render rest of the frame
Expand Down
2 changes: 1 addition & 1 deletion engine/engine/src/wscript
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ def build(bld):

glfw_js = '../../../ext/lib/%s/js/library_glfw.js' % bld.env.PLATFORM

web_libs = [glfw_js, 'library_sys.js', 'library_script.js', 'library_sound.js']
web_libs = [glfw_js, 'library_sys.js', 'library_script.js', 'library_sound.js', 'library_render.js']

main_cpp = 'common/main.cpp'

Expand Down
20 changes: 20 additions & 0 deletions engine/render/src/js/library_render.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
var LibraryRenderer = {
$dmRenderer: {
renderContext: null,
renderCallback: null,

rendererContextEvent: function(event_name) {
if (dmRenderer.renderCallback) {
var event_id = stringToUTF8OnStack(event_name);
{{{ makeDynCall('vii', 'dmRenderer.renderCallback') }}}(dmRenderer.renderContext, event_id);
}
}
},
setupCallbackJS: function(context, callback) {
dmRenderer.renderContext = context;
dmRenderer.renderCallback = callback;
}
}

autoAddDeps(LibraryRenderer, '$dmRenderer');
addToLibrary(LibraryRenderer);
22 changes: 22 additions & 0 deletions engine/render/src/platform/renderer_common.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2020-2024 The Defold Foundation
// Copyright 2014-2020 King
// Copyright 2009-2014 Ragnar Svensson, Christian Murray
// Licensed under the Defold License version 1.0 (the "License"); you may not use
// this file except in compliance with the License.
//
// You may obtain a copy of the License, together with FAQs at
// https://www.defold.com/license
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

#include "render/render_private.h"

namespace dmRender
{
void PlatformSetupContextEventCallback(void* context, ContextEventCallback callback)
{
}
}
25 changes: 25 additions & 0 deletions engine/render/src/platform/renderer_web.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2020-2024 The Defold Foundation
// Copyright 2014-2020 King
// Copyright 2009-2014 Ragnar Svensson, Christian Murray
// Licensed under the Defold License version 1.0 (the "License"); you may not use
// this file except in compliance with the License.
//
// You may obtain a copy of the License, together with FAQs at
// https://www.defold.com/license
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

#include "render/render_private.h"

extern "C" void setupCallbackJS(void* context, dmRender::ContextEventCallback callback);

namespace dmRender
{
void PlatformSetupContextEventCallback(void* context, ContextEventCallback callback)
{
setupCallbackJS(context, callback);
}
}
56 changes: 56 additions & 0 deletions engine/render/src/render/render.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ namespace dmRender
InitializeRenderScriptContext(context->m_RenderScriptContext, graphics_context, params.m_ScriptContext, params.m_CommandBufferSize);
InitializeRenderScriptCameraContext(context, params.m_ScriptContext);
context->m_ScriptWorld = dmScript::NewScriptWorld(context->m_ScriptContext);
context->m_CallbackInfo = 0x0;

context->m_DebugRenderer.m_RenderContext = 0;
if (params.m_VertexShaderDesc != 0 && params.m_VertexShaderDescSize != 0 &&
Expand All @@ -134,6 +135,8 @@ namespace dmRender

context->m_MultiBufferingRequired = 0;

context->m_IsRenderPaused = 0;

dmGraphics::AdapterFamily installed_adapter_family = dmGraphics::GetInstalledAdapterFamily();
if (installed_adapter_family == dmGraphics::ADAPTER_FAMILY_VULKAN ||
installed_adapter_family == dmGraphics::ADAPTER_FAMILY_VENDOR)
Expand All @@ -143,6 +146,8 @@ namespace dmRender

context->m_RenderListDispatch.SetCapacity(255);

SetupContextEventCallback(context, &OnContextEvent);

dmMessage::Result r = dmMessage::NewSocket(RENDER_SOCKET_NAME, &context->m_Socket);
assert(r == dmMessage::RESULT_OK);
return context;
Expand All @@ -152,6 +157,12 @@ namespace dmRender
{
if (render_context == 0x0) return RESULT_INVALID_CONTEXT;

if (render_context->m_CallbackInfo != 0x0)
{
dmScript::DestroyCallback(render_context->m_CallbackInfo);
render_context->m_CallbackInfo = 0x0;
}

FinalizeRenderScriptContext(render_context->m_RenderScriptContext, script_context);
FinalizeRenderScriptCameraContext(render_context);
dmScript::DeleteScriptWorld(render_context->m_ScriptWorld);
Expand Down Expand Up @@ -1124,4 +1135,49 @@ namespace dmRender
std::sort(predicate->m_Tags, predicate->m_Tags+predicate->m_TagCount);
return RESULT_OK;
}

void SetupContextEventCallback(void* context, ContextEventCallback callback)
{
PlatformSetupContextEventCallback(context, callback);
}

void OnContextEvent(void* context, const char* event_name)
{
if (strcmp(event_name, "context_lost") == 0)
{
PauseRender(context);
}
RenderContext* render_context = (RenderContext*)context;
if (render_context->m_CallbackInfo != 0x0)
{
dmScript::LuaCallbackInfo* cbk = render_context->m_CallbackInfo;
if (!dmScript::IsCallbackValid(cbk))
{
return;
}
lua_State* L = dmScript::GetCallbackLuaContext(cbk);
DM_LUA_STACK_CHECK(L, 0);

if (!dmScript::SetupCallback(cbk))
{
return;
}
lua_pushstring(L, event_name);
int ret = dmScript::PCall(L, 2, 0);
(void)ret;
dmScript::TeardownCallback(cbk);
}
}

void PauseRender(void* context)
{
RenderContext* render_context = (RenderContext*)context;
render_context->m_IsRenderPaused = 1;
}

bool IsRenderPaused(void* context)
{
RenderContext* render_context = (RenderContext*)context;
return render_context->m_IsRenderPaused;
}
}
3 changes: 3 additions & 0 deletions engine/render/src/render/render.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,9 @@ namespace dmRender
Result DrawDebug3d(HRenderContext context, const FrustumOptions* frustum_options);
Result DrawDebug2d(HRenderContext context);

void PauseRender(void* context);
bool IsRenderPaused(void* context);

/**
* Render debug square. The upper left corner of the screen is (-1,-1) and the bottom right is (1,1).
* @param context Render context handle
Expand Down
10 changes: 10 additions & 0 deletions engine/render/src/render/render_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ namespace dmRender
RenderScriptContext m_RenderScriptContext;
dmArray<RenderObject*> m_RenderObjects;
dmScript::ScriptWorld* m_ScriptWorld;
dmScript::LuaCallbackInfo* m_CallbackInfo;

dmArray<RenderListEntry> m_RenderList;
dmArray<RenderListDispatch> m_RenderListDispatch;
Expand All @@ -295,6 +296,7 @@ namespace dmRender
uint32_t m_StencilBufferCleared : 1;
uint32_t m_MultiBufferingRequired : 1;
uint32_t m_CurrentRenderCameraUseFrustum : 1;
uint32_t m_IsRenderPaused : 1;
};

struct BufferedRenderBuffer
Expand Down Expand Up @@ -355,12 +357,20 @@ namespace dmRender
};

typedef void (*RangeCallback)(void* ctx, uint32_t val, size_t start, size_t count);
typedef void (*ContextEventCallback)(void* ctx, const char* event_name);

// Invokes the callback for each range. Two ranges are not guaranteed to preceed/succeed one another.
void FindRenderListRanges(uint32_t* first, size_t offset, size_t size, RenderListEntry* entries, FindRangeComparator& comp, void* ctx, RangeCallback callback );

bool FindTagListRange(RenderListRange* ranges, uint32_t num_ranges, uint32_t tag_list_key, RenderListRange& range);

/*
* Possible event_name values: "context_lost", "context_restored"
* See dmloader.js for event's name constants.
*/
void OnContextEvent(void* context, const char* event_name);
void SetupContextEventCallback(void* context, ContextEventCallback callback);
void PlatformSetupContextEventCallback(void* context, ContextEventCallback callback);

// ******************************************************************************************************

Expand Down
34 changes: 34 additions & 0 deletions engine/render/src/render/render_script.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3072,6 +3072,39 @@ namespace dmRender
return DM_LUA_ERROR("Command buffer is full (%d).", i->m_CommandBuffer.Capacity());
}

int RenderScript_SetListener(lua_State* L)
{
DM_LUA_STACK_CHECK(L, 0);

RenderScriptInstance* script_instance = RenderScriptInstance_Check(L);
dmScript::LuaCallbackInfo* cbk = script_instance->m_RenderContext->m_CallbackInfo;

int type = lua_type(L, 1);
if (type == LUA_TNONE || type == LUA_TNIL)
{
if (cbk != 0x0)
{
dmScript::DestroyCallback(cbk);
script_instance->m_RenderContext->m_CallbackInfo = 0x0;
}
}
else if (type == LUA_TFUNCTION)
{
if (cbk != 0x0)
{
dmScript::DestroyCallback(cbk);
script_instance->m_RenderContext->m_CallbackInfo = 0x0;
}
cbk = dmScript::CreateCallback(L, 1);
script_instance->m_RenderContext->m_CallbackInfo = cbk;
}
else
{
return DM_LUA_ERROR("argument 1 to render.set_listener() must be either nil or function");
}
return 0;
}

static const luaL_reg Render_methods[] =
{
{"enable_state", RenderScript_EnableState},
Expand Down Expand Up @@ -3111,6 +3144,7 @@ namespace dmRender
{"enable_material", RenderScript_EnableMaterial},
{"disable_material", RenderScript_DisableMaterial},
{"set_camera", RenderScript_SetCamera},
{"set_listener", RenderScript_SetListener},
{0, 0}
};

Expand Down
11 changes: 10 additions & 1 deletion engine/render/src/wscript
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,17 @@ def configure(cont):
pass

def build(bld):
sources = bld.path.ant_glob('render/*.cpp') + bld.path.parent.ant_glob('proto/render/*.proto')
if 'web' in bld.env.PLATFORM:
sources += ['platform/renderer_web.cpp']
else:
sources += ['platform/renderer_common.cpp']

obj = bld.stlib(features = 'cxx ddf',
includes = ['.', '../build/proto'],
proto_gen_py = True,
protoc_includes = '../proto',
source = bld.path.ant_glob('render/*.cpp') + bld.path.parent.ant_glob('proto/render/*.proto'),
source = sources,
target = 'render')

bld.recurse('test')
Expand All @@ -30,6 +36,9 @@ def build(bld):
bld.install_files('${PREFIX}/share/proto/render', '../proto/render/render_ddf.proto')
bld.install_files('${PREFIX}/share/proto/render', '../proto/render/font_ddf.proto')

if 'web' in bld.env.PLATFORM:
bld.install_files('${PREFIX}/lib/%s/js' % bld.env['PLATFORM'], 'js/library_render.js', postpone = False)

apidoc_extract_task(bld, [
'../proto/render/material_ddf.proto',
'../proto/render/render_ddf.proto',
Expand Down

0 comments on commit ba9c476

Please sign in to comment.