Commit Graph

15 Commits

Author SHA1 Message Date
Aaron Hill e2954821ea
core: Take two - delay reading image back from render backend using `SyncHandle` (#9184)
* Take two: Delay reading image back from render backend using `SyncHandle`

This allows us to avoid blocking immediately after a `BitmapData.draw` call.
Instead, we only attempt to use the `SyncHandle` when performing an operation
that requires the CPU-side pixels (e.g. BitmapData.getPixel or BitmapData.setPixel).

In the best case, the SWF will never explicitly access the pixels of
the target BitmapData, removing the need to ever copy back the render backend
image to our BitmapData. If the SWF doesn't require access to the pixels immediately,
we can delay copying the pixels until they're actually needed, hopefully allowing
the render backend to finish processing the BitmapData.draw operation in
the backenground before we need the result.

Now that the CPU and GPU pixels can be intentionally out of sync with
each other, we need to ensure that we don't accidentally expose 'stale'
CPU-side pixels to ActionScript (which needs to remain unaware of
our internal laziness). We now use a wrapper type `BitmapDataWrapper`
to enforce that the `SyncHandle` is consumed before accessing the
underlying `BitmapData.

* core: Skip GPU->CPU sync for source and target BitmapData during draw

* Introduce DirtyState enum
2023-01-21 21:08:04 +00:00
Nathan Adams 9cd850d30e render: Make render_offscreen return a sync handle which can be used to get the texture at a later time 2023-01-11 16:53:33 -05:00
Nathan Adams a69d30bb67 render: Add debug info method to renderer backends 2023-01-05 05:51:32 +01:00
Aaron Hill 1b3070ab85 core: Make `BitmapHandle` hold a trait object instead of an id
`BitmapHandle` now holds `Arc<dyn BitmapHandleImpl>`.
This allows us to move all of the per-bitmap backend data into
`BitmapHandle`, instead of holding an id to a backend-specific
hashmap.

This fixes the memory leak issue with bitmaps. Once the AVM side of a
bitmap (`Bitmap`/`BitmapData`) gets garbage-collected, the
`BitmapHandle` will get dropped, freeing all of the GPU resources
assoicated with the bitmap.
2022-12-03 19:44:44 -06:00
Aaron Hill b8745f0ff1 avm2: Partially implement Stage3D for wgpu backend
This PR implements core 'stage3D' APIs. We are now able
to render at least two demos from the Context3D docs - a simple
triangle render, and a rotating cube.

Implemented in this PR:
* Stage3D access and Context3D creation
* IndexBuffer3D and VertexBuffer3D creation, uploading, and usage
* Program3D uploading and usage (via `naga-agal`)
* Context3D: configureBackBuffer, clear, drawTriangles, and present

Not yet implemented:
* Any 'dispose()' methods
* Depth and stencil buffers
* Context3D texture apis
* Scissor rectangle

General implementation strategy:

A new `Object` variant is added for each of the Stage3D objects
(VertexBuffer3D, Program3D, etc). This stores a handle to the
parent `Context3D`, and (depending on the object) a handle
to the underlying native resource, via `Rc<dyn
SomeRenderBackendTrait>`).

Calling methods on Context3D does not usually result in an immediate
call to a `wgpu` method. Instead, we queue up commands in our
`Context3D` instance, and execute them all on a call to `present`.
This avoids some nasty wgpu lifetime issues, and is very similar
to the approah we use for normal rendering.

The actual rendering happens on a `Texture`, with dimensions
determined by `createBackBuffer`. During 'Stage' rendering,
we render all of these Stage3D textures *behind* the normal
stage (but in front of the overall stage background color).
2022-11-25 21:43:00 -07:00
Aaron Hill 3bef8c4fd6 render: Remove `get_bitmap_pixels` and store data in `Character::Bitmap`
We only called `get_bitmap_pixels` when creating a `BitmapData`
for an SWF-provided `Bitmap`. We now store the initial pixels
in `Character::Bitmap`, and use them to initialize a `BitmapData`
when needed.

This lets us simplify the wgpu backend, which no longer needs
to store a `Bitmap` object. In addition to saving space for
`BitmapData` objects that lack an SWF `Bitmap`, this will make
it easier to move data from `bitmap_registry` into `BitmapHandle`
itself.
2022-11-25 16:08:42 -07:00
Aaron Hill 45515be0a3 render: Improve support for BitmapData.draw
This PR fixes a numbe of interconnected bugs:
* We weren't consistently uploading a dirty BitmapData to the render
  backend before drawing to/from it.
* BitmapData.draw should *not* add a fill color - it should draw over
  the current contents of the BitmapData
* After drawing to a non-transparent BitmapData, we need to manually
  set the opacity back to 255 for each pixel (the drawing process
  takes transparency into account, but the opacity information is
  thrown away at the end).
2022-10-17 12:53:38 -05:00
relrelb 86ef4bd7fe core: Simplify `Bitmap` creation
Change `Bitmap::new()` to accept a `ruffle_render::bitmap::Bitmap`
directly, instead of `width`, `height` and `bitmap_handle`. As a
consequence, all `RenderBackend::register_bitmap_*` methods are no
longer necessary - we can use `ruffle_redner::utils::*` to obtain
a `ruffle_render::bitmap::Bitmap` right before calling `Bitmap::new()`.
2022-10-17 20:05:30 +03:00
Aaron Hill 423d7e4cc4 render: Treat `update_texture` with invalid `BitmapHandle` as an error
This should be impossible to trigger from ActionScript, so
we shouldn't ignore it.
2022-09-16 22:03:15 -06:00
Nathan Adams 267ea0fd13 render: Introduced render commands, moved to a command list model instead of direct rendering 2022-09-11 09:07:53 +02:00
Aaron Hill 93607aa86e
avm2: Implement `BitmapData.draw` for `wgpu` backend (#7254)
* avm2: Implement `BitmapData.draw` for `wgpu` backend

This method requires us to have the ability to render directly to a
texture. Fortunately, the `wgpu` backend already supports this in
the form of `TextureTarget`. However, the rendering code required
some refactoring in order to avoid creating duplicate `wgpu` resources.

The current implementation blocks on copying the pixels back
from the GPU to the CPU, so that we can immediately set them in
the Ruffle `BitmapData`. This is likely very inefficient, but will
work for a first implementation.

In the future, we could explore allowing the CPU image data and GPU
texture to be out of sync, and only synchronized when explicitly
necessary (e.g. on `getPixel` or `setPixel` calls).

* Rename `with_offscreen_backend` to `render_offscreen` and use Bitmap

* Don't panic when backend doesn't implement `render_offscreen`
2022-09-06 16:38:48 -05:00
= 461c977be0 render: unregister_bitmap is infallible, removed error path 2022-08-25 23:43:21 +02:00
Aaron Hill 98c7f443ce core: Only store viewport dimensions in `RenderBackend`
Previously, the viewport height and width were stored in
both `Stage` and the `RenderBackend`. Any changes to the viewport
dimensions (e.g. due to window resizing) needed to be updated in both
places to keep our handling of the viewport consistent.

This PR adds a new `ViewportDimensions` type, which holds the
width, height, and scale factor. It is stored inside the
`RenderBackend` impl, and is retrieved using the newly added
method `RenderBackend.get_viewport_dimensions`. After a `Player`
has been constructed, any code that needes access to the viewport
dimensions will ultimate go through this method.

Unfortunately, `Stage` needs to use the viewport dimensions
in `build_matrices`. Therefore, any code modifying the viewport
dimensions should go through `player.set_viewport_dimensions`,
which ensures that the stage matrices are rebuilt after the render
backend is updated.
2022-08-22 13:44:30 -07:00
Aaron Hill f7205a02a9 render: Add BlendMode infrastructure and implement BlendMode.ADD
Each render backend keeps track of a stack of BlenModes,
which are pushed and popped by 'core' as we render objects
in the displaay tree. For now, I've just implemented BlendMode.ADD,
which maps directly onto blend mode supported by each backend.

All other blend modes (besides 'NORMAL') will produce a warning
when we try to render using them. This may produce a very large amount
of log output, but it's simpler than emitting each warning only once,
and will help to point developers in the right direction when they
get otherwise inexplicable rendering issues (due to a blend mode
not being implemented).

The wgpu implementation is by far the most complicated, as we need
to construct a `RenderPipeline` for each possible
`(BlendMode, MaskState)`. I haven't been able to find any documentation
about the maximum supported number of (simultaneous) WebGPU render
pipelines - if this becomes an issue, we may need to register them
on-demand when a particular blend mode is requested.
2022-08-18 16:38:17 -07:00
Nathan Adams 824b4aa8d1 render: Moved render backend from core to render 2022-08-14 18:38:14 -07:00