28
28
#include " WebGPUStrings.h"
29
29
#include " WebGPUSwapChain.h"
30
30
#include " WebGPUTexture.h"
31
+ #include " WebGPUTextureHelpers.h"
31
32
#include " WebGPUVertexBuffer.h"
32
33
#include " WebGPUVertexBufferInfo.h"
33
34
#include < backend/platforms/WebGPUPlatform.h>
@@ -79,8 +80,9 @@ WebGPUDriver::WebGPUDriver(WebGPUPlatform& platform,
79
80
mPipelineCache { mDevice },
80
81
mRenderPassMipmapGenerator { mDevice },
81
82
mSpdComputePassMipmapGenerator { mDevice },
83
+ mBlitter { mDevice },
82
84
mHandleAllocator { " Handles" , driverConfig.handleArenaSize ,
83
- driverConfig.disableHandleUseAfterFreeCheck , driverConfig.disableHeapHandleTags } {
85
+ driverConfig.disableHandleUseAfterFreeCheck , driverConfig.disableHeapHandleTags }{
84
86
mDevice .GetLimits (&mDeviceLimits );
85
87
}
86
88
@@ -741,21 +743,65 @@ void WebGPUDriver::update3DImage(Handle<HwTexture> textureHandle, const uint32_t
741
743
const uint32_t xoffset, const uint32_t yoffset, const uint32_t zoffset,
742
744
const uint32_t width, const uint32_t height, const uint32_t depth,
743
745
PixelBufferDescriptor&& pixelBufferDescriptor) {
744
- PixelBufferDescriptor* data = &pixelBufferDescriptor;
746
+ PixelBufferDescriptor* inputData{ &pixelBufferDescriptor } ;
745
747
PixelBufferDescriptor reshapedData;
746
748
if (reshape (pixelBufferDescriptor, reshapedData)) {
747
- data = &reshapedData;
749
+ inputData = &reshapedData;
748
750
}
749
- auto texture = handleCast<WebGPUTexture>(textureHandle);
751
+ const auto texture{ handleCast<WebGPUTexture>(textureHandle) };
752
+ FILAMENT_CHECK_PRECONDITION ((texture->getTexture ().GetWidth () + xoffset) >= width)
753
+ << " Blitting requires the destination region to have enough width ("
754
+ << texture->getTexture ().GetWidth () << " to accommodate the requested " << width
755
+ << " width to write/blit (accounting for xoffset, which is " << xoffset << " )." ;
756
+ FILAMENT_CHECK_PRECONDITION ((texture->getTexture ().GetHeight () + yoffset) >= height)
757
+ << " Blitting requires the destination region to have enough height ("
758
+ << texture->getTexture ().GetHeight () << " to accommodate the requested " << height
759
+ << " height to write/blit (accounting for yoffset, which is " << yoffset << " )." ;
760
+ FILAMENT_CHECK_PRECONDITION ((texture->getTexture ().GetDepthOrArrayLayers () + zoffset) >= depth)
761
+ << " Blitting requires the destination region to have enough depth/arrayLayers ("
762
+ << texture->getTexture ().GetDepthOrArrayLayers () << " to accommodate the requested "
763
+ << depth << " depth to write/blit (accounting for zoffset, which is " << zoffset << " )." ;
750
764
751
765
// TODO: Writing to a depth texture is illegal and errors. I'm not sure why Filament is trying
752
766
// to do so, but early returning is working?
753
- if (texture->getAspect () == wgpu::TextureAspect::DepthOnly){
767
+ if (texture->getAspect () == wgpu::TextureAspect::DepthOnly) {
754
768
scheduleDestroy (std::move (pixelBufferDescriptor));
755
769
return ;
756
770
}
757
- size_t blockWidth = texture->getBlockWidth ();
758
- size_t blockHeight = texture->getBlockHeight ();
771
+
772
+ const wgpu::TextureFormat inputPixelFormat{ toWebGPUFormat (inputData->format ,
773
+ inputData->type ) };
774
+ const wgpu::TextureFormat outputLinearFormat{ toWebGPULinearFormat (
775
+ texture->getTexture ().GetFormat ()) };
776
+ const bool conversionNecessary{
777
+ inputPixelFormat != outputLinearFormat && inputData->type != PixelDataType::COMPRESSED
778
+ }; // compressed formats should never need conversion
779
+ const bool doBlit{ conversionNecessary };
780
+ #if FWGPU_ENABLED(FWGPU_DEBUG_VALIDATION)
781
+ if (texture->width > 1000 && texture->height > 500 ) {
782
+ FWGPU_LOGD << " Update3DImage(..., level=" << level << " , xoffset=" << xoffset
783
+ << " , yoffset=" << yoffset << " , zoffset=" << zoffset << " , width=" << width
784
+ << " , height=" << height << " , depth=" << depth << " , ...):" ;
785
+ FWGPU_LOGD << " PixelBufferDescriptor format (input): " << toString (inputData->format );
786
+ FWGPU_LOGD << " PixelBufferDescriptor type (input): " << toString (inputData->type );
787
+ FWGPU_LOGD << " Pixel WebGPUFormat (input): "
788
+ << webGPUTextureFormatToString (inputPixelFormat);
789
+ FWGPU_LOGD << " Texture View format (output): "
790
+ << webGPUTextureFormatToString (texture->getViewFormat ());
791
+ FWGPU_LOGD << " Texture format (output): "
792
+ << webGPUTextureFormatToString (texture->getTexture ().GetFormat ());
793
+ FWGPU_LOGD << " Linear Texture format (output): "
794
+ << webGPUTextureFormatToString (outputLinearFormat);
795
+ FWGPU_LOGD << " Conversion Necessary: " << conversionNecessary;
796
+ FWGPU_LOGD << " Do Blit: " << doBlit;
797
+ }
798
+ #endif
799
+ FILAMENT_CHECK_PRECONDITION (inputData->type == PixelDataType::COMPRESSED ||
800
+ inputPixelFormat != wgpu::TextureFormat::Undefined)
801
+ << " Failed to determine uncompressed input pixel format for WebGPU. Pixel format "
802
+ << toString (inputData->format ) << " type " << toString (inputData->type );
803
+ const size_t blockWidth{ texture->getBlockWidth () };
804
+ const size_t blockHeight{ texture->getBlockHeight () };
759
805
// WebGPU specification requires that for compressed textures, the x and y offsets
760
806
// must be a multiple of the compressed texture format's block width and height.
761
807
// See: https://www.w3.org/TR/webgpu/#abstract-opdef-validating-gputexelcopytextureinfo
@@ -767,22 +813,91 @@ void WebGPUDriver::update3DImage(Handle<HwTexture> textureHandle, const uint32_t
767
813
<< " yoffset must be aligned to blockHeight, but offset is " << blockHeight
768
814
<< " and offset is " << yoffset;
769
815
}
770
-
771
- auto copyInfo = wgpu::TexelCopyTextureInfo{
772
- .texture = texture->getTexture (),
773
- .mipLevel = level,
774
- .origin = { .x = xoffset, .y = yoffset, .z = zoffset },
775
- .aspect = texture->getAspect () };
776
- uint32_t bytesPerRow = static_cast <uint32_t >(
777
- PixelBufferDescriptor::computePixelSize (data->format , data->type ) * width);
778
- auto extent = wgpu::Extent3D{ .width = width, .height = height, .depthOrArrayLayers = depth };
779
-
780
- const uint8_t * dataBuff = static_cast <const uint8_t *>(data->buffer );
781
- size_t dataSize = data->size ;
782
-
783
- auto layout = wgpu::TexelCopyBufferLayout{ .bytesPerRow = bytesPerRow, .rowsPerImage = height };
784
-
785
- mQueue .WriteTexture (©Info, dataBuff, dataSize, &layout, &extent);
816
+ const auto extent{
817
+ wgpu::Extent3D{ .width = width, .height = height, .depthOrArrayLayers = depth }
818
+ };
819
+ const uint32_t bytesPerRow{ static_cast <uint32_t >(
820
+ PixelBufferDescriptor::computePixelSize (inputData->format , inputData->type ) * width) };
821
+ const uint8_t * dataBuff{ static_cast <const uint8_t *>(inputData->buffer ) };
822
+ const size_t dataSize{ inputData->size };
823
+ const auto layout{ wgpu::TexelCopyBufferLayout{
824
+ .bytesPerRow = bytesPerRow,
825
+ .rowsPerImage = height,
826
+ } };
827
+ if (doBlit) {
828
+ const wgpu::TextureDescriptor stagingTextureDescriptor{
829
+ .label = " blit_staging_input_texture" ,
830
+ .usage = texture->getTexture ().GetUsage (),
831
+ .dimension = texture->getTexture ().GetDimension (),
832
+ .size = extent,
833
+ .format = inputPixelFormat,
834
+ .mipLevelCount = 1 ,
835
+ .sampleCount = texture->getTexture ().GetSampleCount (),
836
+ .viewFormatCount = 0 ,
837
+ .viewFormats = nullptr ,
838
+ };
839
+ const wgpu::Texture stagingTexture{ mDevice .CreateTexture (&stagingTextureDescriptor) };
840
+ FILAMENT_CHECK_POSTCONDITION (stagingTexture)
841
+ << " Failed to create staging input texture for blit?" ;
842
+ const auto copyInfo{ wgpu::TexelCopyTextureInfo{
843
+ .texture = stagingTexture,
844
+ .mipLevel = level,
845
+ .origin = { .x = 0 , .y = 0 , .z = 0 },
846
+ .aspect = texture->getAspect (),
847
+ } };
848
+ mQueue .WriteTexture (©Info, dataBuff, dataSize, &layout, &extent);
849
+ bool reusedCommandEncoder{ true };
850
+ if (!mCommandEncoder ) {
851
+ reusedCommandEncoder = false ;
852
+ const wgpu::CommandEncoderDescriptor commandEncoderDescriptor{
853
+ .label = " blit_command" ,
854
+ };
855
+ mCommandEncoder = mDevice .CreateCommandEncoder (&commandEncoderDescriptor);
856
+ FILAMENT_CHECK_POSTCONDITION (mCommandEncoder )
857
+ << " Failed to create command encoder for blit?" ;
858
+ }
859
+ WebGPUBlitter::BlitArgs blitArgs{
860
+ .source = {
861
+ .texture = stagingTexture,
862
+ .origin = { .x = 0 , .y = 0 },
863
+ .extent = {.width = width, .height = height},
864
+ .mipLevel = 0 ,
865
+ },
866
+ .destination = {
867
+ .texture = texture->getTexture (),
868
+ .origin = {.x =xoffset,.y =yoffset},
869
+ .extent = {.width = width, .height = height},
870
+ .mipLevel = level,
871
+ },
872
+ .filter = SamplerMagFilter::NEAREST,
873
+ };
874
+ for (uint32_t layerIndex{ 0 }; layerIndex < depth; ++layerIndex) {
875
+ blitArgs.source .layerOrDepth = layerIndex;
876
+ blitArgs.destination .layerOrDepth = layerIndex + zoffset;
877
+ mBlitter .blit (mQueue , mCommandEncoder , blitArgs);
878
+ }
879
+ if (!reusedCommandEncoder) {
880
+ const wgpu::CommandBufferDescriptor commandBufferDescriptor{
881
+ .label = " blit_command_buffer" ,
882
+ };
883
+ const wgpu::CommandBuffer blitCommand{ mCommandEncoder .Finish (
884
+ &commandBufferDescriptor) };
885
+ FILAMENT_CHECK_POSTCONDITION (blitCommand)
886
+ << " Failed to create command buffer for blit?" ;
887
+ mQueue .Submit (1 , &blitCommand);
888
+ mCommandEncoder = nullptr ;
889
+ }
890
+ stagingTexture.Destroy ();
891
+ } else {
892
+ // not doing blit (copy byte-by-byte)...
893
+ const auto copyInfo { wgpu::TexelCopyTextureInfo{
894
+ .texture = texture->getTexture (),
895
+ .mipLevel = level,
896
+ .origin = { .x = xoffset, .y = yoffset, .z = zoffset, },
897
+ .aspect = texture->getAspect (),
898
+ }};
899
+ mQueue .WriteTexture (©Info, dataBuff, dataSize, &layout, &extent);
900
+ }
786
901
scheduleDestroy (std::move (pixelBufferDescriptor));
787
902
}
788
903
@@ -1307,7 +1422,45 @@ void WebGPUDriver::blit(Handle<HwTexture> destinationTextureHandle, const uint8_
1307
1422
const uint8_t sourceLayer, const math::uint2 destinationOrigin,
1308
1423
Handle<HwTexture> sourceTextureHandle, const uint8_t destinationLevel,
1309
1424
const uint8_t destinationLayer, const math::uint2 sourceOrigin, const math::uint2 size) {
1310
- // todo
1425
+ // TODO uncomment when texture format is taken into account with sampler settings in the
1426
+ // blitter
1427
+ // bool reusedCommandEncoder{ true };
1428
+ // if (!mCommandEncoder) {
1429
+ // reusedCommandEncoder = false;
1430
+ // const wgpu::CommandEncoderDescriptor commandEncoderDescriptor{
1431
+ // .label = "blit_command",
1432
+ // };
1433
+ // mCommandEncoder = mDevice.CreateCommandEncoder(&commandEncoderDescriptor);
1434
+ // FILAMENT_CHECK_POSTCONDITION(mCommandEncoder)
1435
+ // << "Failed to create command encoder for blit?";
1436
+ // }
1437
+ // const WebGPUBlitter::BlitArgs blitArgs{
1438
+ // .source = {
1439
+ // .texture = handleCast<WebGPUTexture>(sourceTextureHandle)->getTexture(),
1440
+ // .origin = {.x = sourceOrigin.x, .y=sourceOrigin.y},
1441
+ // .extent = {.width=size.x, .height =size.y},
1442
+ // .mipLevel = sourceLevel,
1443
+ // .layerOrDepth = sourceLayer,
1444
+ // },
1445
+ // .destination = {
1446
+ // .texture = handleCast<WebGPUTexture>(destinationTextureHandle)->getTexture(),
1447
+ // .origin = {.x = destinationOrigin.x, .y=destinationOrigin.y},
1448
+ // .extent = {.width=size.x, .height =size.y},
1449
+ // .mipLevel = destinationLevel,
1450
+ // .layerOrDepth = destinationLayer,
1451
+ // },
1452
+ // .filter = SamplerMagFilter::NEAREST,
1453
+ // };
1454
+ // mBlitter.blit(mQueue, mCommandEncoder, blitArgs);
1455
+ // if (!reusedCommandEncoder) {
1456
+ // const wgpu::CommandBufferDescriptor commandBufferDescriptor{
1457
+ // .label = "blit_command_buffer",
1458
+ // };
1459
+ // const wgpu::CommandBuffer blitCommand{ mCommandEncoder.Finish(&commandBufferDescriptor) };
1460
+ // FILAMENT_CHECK_POSTCONDITION(blitCommand) << "Failed to create command buffer for blit?";
1461
+ // mQueue.Submit(1, &blitCommand);
1462
+ // mCommandEncoder = nullptr;
1463
+ // }
1311
1464
}
1312
1465
1313
1466
void WebGPUDriver::bindPipeline (PipelineState const & pipelineState) {
0 commit comments