Fixes for Web
This commit is contained in:
@@ -383,12 +383,17 @@ protected:
|
||||
_streamingTexture->GetOwner()->GetMipData(absoluteMipIndex, data);
|
||||
if (data.IsInvalid())
|
||||
return Result::MissingData;
|
||||
PixelFormat dataFormat = _streamingTexture->GetHeader()->Format;
|
||||
|
||||
// Cache data
|
||||
const int32 arraySize = texture->ArraySize();
|
||||
uint32 rowPitch, slicePitch;
|
||||
if (!_streamingTexture->GetOwner()->GetMipDataCustomPitch(absoluteMipIndex, rowPitch, slicePitch))
|
||||
texture->ComputePitch(_mipIndex, rowPitch, slicePitch);
|
||||
{
|
||||
int32 mipWidth, mipHeight;
|
||||
texture->GetMipSize(_mipIndex, mipWidth, mipHeight);
|
||||
RenderTools::ComputePitch(dataFormat, mipWidth, mipHeight, rowPitch, slicePitch);
|
||||
}
|
||||
_data.Link(data);
|
||||
|
||||
// Update all array slices
|
||||
@@ -396,9 +401,9 @@ protected:
|
||||
int32 dataPerSlice = data.Length() / arraySize; // In most cases it's a slice pitch, except when using transcoding (eg. Basis), then each slice has to use the same amount of memory
|
||||
for (int32 arrayIndex = 0; arrayIndex < arraySize; arrayIndex++)
|
||||
{
|
||||
if (TextureTool::UpdateTexture(context->GPU, texture, arrayIndex, _mipIndex, Span<byte>(dataSource, dataPerSlice), rowPitch, slicePitch, _streamingTexture->GetHeader()->Format))
|
||||
if (TextureTool::UpdateTexture(context->GPU, texture, arrayIndex, _mipIndex, Span<byte>(dataSource, dataPerSlice), rowPitch, slicePitch, dataFormat))
|
||||
{
|
||||
LOG(Error, "Cannot stream mip {} of texture {} (format: {})", _mipIndex, texture->ToString(), ScriptingEnum::ToString(_streamingTexture->GetHeader()->Format));
|
||||
LOG(Error, "Cannot stream mip {} of texture {} (format: {})", _mipIndex, texture->ToString(), ScriptingEnum::ToString(dataFormat));
|
||||
return Result::Failed;
|
||||
}
|
||||
dataSource += dataPerSlice;
|
||||
|
||||
@@ -1090,12 +1090,13 @@ void GPUContextWebGPU::FlushBindGroup()
|
||||
{
|
||||
auto descriptors = _pipelineState->BindGroupDescriptors[groupIndex];
|
||||
key.Layout = _pipelineState->BindGroupLayouts[groupIndex];
|
||||
if (!descriptors || !key.Layout)
|
||||
continue;
|
||||
|
||||
// Build descriptors
|
||||
uint32 dynamicOffsetsCount = 0;
|
||||
BuildBindGroup(groupIndex, *descriptors, key, dynamicOffsets, dynamicOffsetsCount);
|
||||
if (descriptors)
|
||||
BuildBindGroup(groupIndex, *descriptors, key, dynamicOffsets, dynamicOffsetsCount);
|
||||
else
|
||||
key.EntriesCount = 0;
|
||||
|
||||
// Bind group
|
||||
WGPUBindGroup bindGroup = _pipelineState->GetBindGroup(key);
|
||||
|
||||
@@ -302,12 +302,11 @@ bool GPUDeviceWebGPU::Init()
|
||||
limits.maxComputeWorkgroupSizeY >= 256 &&
|
||||
limits.maxComputeWorkgroupSizeZ >= 8 &&
|
||||
limits.maxBufferSize >= 64 * 1024 * 1024; // 64MB
|
||||
Limits.HasInstancing = true;
|
||||
Limits.HasInstancing = features.Contains(WGPUFeatureName_PrimitiveIndex); // TODO: investigate why Firefox doesn't draw instanced draws (this check is kind of a hack)
|
||||
Limits.HasDrawIndirect = true;
|
||||
Limits.HasDepthAsSRV = true;
|
||||
Limits.HasReadOnlyDepth = true;
|
||||
Limits.HasDepthClip = features.Contains(WGPUFeatureName_DepthClipControl);
|
||||
Limits.HasReadOnlyDepth = true;
|
||||
Limits.MaximumSamplerAnisotropy = 4;
|
||||
Limits.MaximumTexture1DSize = limits.maxTextureDimension1D;
|
||||
Limits.MaximumTexture2DSize = limits.maxTextureDimension2D;
|
||||
|
||||
@@ -16,7 +16,7 @@ public class GraphicsDeviceWebGPU : GraphicsDeviceBaseModule
|
||||
/// 1 - via Asyncify (causes the WASM to be much larger) <br/>
|
||||
/// 2 - via JSPI (experimental) <br/>
|
||||
/// </summary>
|
||||
public int WithAsyncify = 2;
|
||||
public static int WithAsyncify = 2;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Setup(BuildOptions options)
|
||||
|
||||
@@ -77,6 +77,7 @@ public class Main : EngineModule
|
||||
break;
|
||||
case TargetPlatform.Web:
|
||||
options.SourcePaths.Add(Path.Combine(FolderPath, "Web"));
|
||||
options.PrivateDefinitions.Add("WEB_LOOP_MODE=" + GraphicsDeviceWebGPU.WithAsyncify);
|
||||
break;
|
||||
default: throw new InvalidPlatformException(options.Platform.Target);
|
||||
}
|
||||
|
||||
@@ -7,17 +7,19 @@
|
||||
|
||||
// Reference: https://github.com/kainino0x/webgpu-cross-platform-demo/blob/f5c69c6fccbb2584c1b6f9e559f9a41a38a9b5ad/main.cpp#L692-L704
|
||||
// Reference: https://github.com/kainino0x/webgpu-cross-platform-demo/blob/c26ea3e29ed9f73f9b39bddf7964b482ce3c6964/main.cpp#L737-L758
|
||||
#define WEB_LOOP_MODE 2 // 0 - default, 1 - Asyncify, 2 - JSPI
|
||||
#if WEB_LOOP_MODE != 0
|
||||
#ifndef WEB_LOOP_MODE // 0 - default, 1 - Asyncify, 2 - JSPI
|
||||
#error "Unknown WEB_LOOP_MODE"
|
||||
#endif
|
||||
#if WEB_LOOP_MODE == 2
|
||||
// Workaround for JSPI not working in emscripten_set_main_loop. Loosely based on this code:
|
||||
// https://github.com/emscripten-core/emscripten/issues/22493#issuecomment-2330275282
|
||||
// This code only works with JSPI is enabled.
|
||||
typedef bool (*FrameCallback)(); // If callback returns true, continues the loop.
|
||||
EM_JS(void, requestAnimationFrameLoopWithJSPI, (FrameCallback callback), {
|
||||
EM_JS(void, requestAnimationFrameLoopWithJSPI, (FrameCallback frame), {
|
||||
#if WEB_LOOP_MODE == 2
|
||||
var callback = WebAssembly.promising(getWasmTableEntry(callback));
|
||||
var callback = WebAssembly.promising(getWasmTableEntry(frame));
|
||||
#elif WEB_LOOP_MODE == 1
|
||||
var callback = () = > globalThis['Module']['ccall']("callback", "boolean", [], [], { async: true });
|
||||
var callback = () = > globalThis['Module']['ccall']("frame", "boolean", [], [], { async: true });
|
||||
#endif
|
||||
async function tick() {
|
||||
// Start the frame callback. 'await' means we won't call
|
||||
@@ -31,7 +33,7 @@ EM_JS(void, requestAnimationFrameLoopWithJSPI, (FrameCallback callback), {
|
||||
|
||||
class PlatformMain
|
||||
{
|
||||
#if WEB_LOOP_MODE == 0
|
||||
#if WEB_LOOP_MODE != 2
|
||||
static void Loop()
|
||||
{
|
||||
// Tick engine
|
||||
@@ -75,7 +77,7 @@ public:
|
||||
return result;
|
||||
|
||||
// Setup main loop to be called by Emscripten
|
||||
#if WEB_LOOP_MODE == 0
|
||||
#if WEB_LOOP_MODE != 2
|
||||
emscripten_set_main_loop(Loop, -1, false);
|
||||
#else
|
||||
requestAnimationFrameLoopWithJSPI(Loop);
|
||||
|
||||
@@ -419,15 +419,15 @@ bool TextureTool::UpdateTexture(GPUContext* context, GPUTexture* texture, int32
|
||||
auto textureSampler = PixelFormatSampler::Get(textureFormat);
|
||||
if (!dataSampler || !textureSampler)
|
||||
return true;
|
||||
auto bytesPerPixel = PixelFormatExtensions::SizeInBytes(textureFormat);
|
||||
|
||||
int32 mipWidth, mipHeight, mipDepth;
|
||||
texture->GetMipSize(mipIndex, mipWidth, mipHeight, mipDepth);
|
||||
|
||||
auto tempRowPitch = mipWidth * bytesPerPixel;
|
||||
auto tempRowPitch = mipWidth * textureSampler->PixelSize;
|
||||
auto tempSlicePitch = tempRowPitch * mipHeight;
|
||||
tempData.Resize(tempSlicePitch * mipDepth);
|
||||
|
||||
ASSERT(data.Length() / rowPitch >= mipHeight);
|
||||
for (int32 y = 0; y < mipHeight; y++)
|
||||
{
|
||||
for (int32 x = 0; x < mipWidth; x++)
|
||||
@@ -514,7 +514,9 @@ PixelFormat TextureTool::GetTextureFormat(TextureFormatType textureType, PixelFo
|
||||
EnumHasAllFlags(GPUDevice::Instance->GetFormatFeatures(PixelFormat::R32_Float).Support, minSupport) &&
|
||||
PixelFormatSampler::Get(dataFormat))
|
||||
return PixelFormat::R32_Float;
|
||||
if (dataFormat == PixelFormat::R16G16_UNorm && EnumHasAllFlags(GPUDevice::Instance->GetFormatFeatures(PixelFormat::R32G32_UInt).Support, minSupport))
|
||||
if (dataFormat == PixelFormat::R16G16_UNorm &&
|
||||
EnumHasAllFlags(GPUDevice::Instance->GetFormatFeatures(PixelFormat::R32G32_Float).Support, minSupport) &&
|
||||
PixelFormatSampler::Get(dataFormat))
|
||||
return PixelFormat::R32G32_Float;
|
||||
if ((dataFormat == PixelFormat::R16G16B16A16_UNorm || dataFormat == PixelFormat::R16G16B16A16_Float) &&
|
||||
EnumHasAllFlags(GPUDevice::Instance->GetFormatFeatures(PixelFormat::R32G32B32A32_Float).Support, minSupport) &&
|
||||
|
||||
Reference in New Issue
Block a user