siyao
4 年前
当前提交
8827b37e
共有 49 个文件被更改,包括 2635 次插入 和 378 次删除
-
47com.unity.uiwidgets/Runtime/async2/future.cs
-
82com.unity.uiwidgets/Runtime/editor/editor_window.cs
-
172com.unity.uiwidgets/Runtime/engine2/UIWidgetsPanel.cs
-
88com.unity.uiwidgets/Runtime/gestures/converter.cs
-
8com.unity.uiwidgets/Runtime/services/asset_bundle.cs
-
72com.unity.uiwidgets/Runtime/ui/pointer.cs
-
60com.unity.uiwidgets/Runtime/ui2/compositing.cs
-
120com.unity.uiwidgets/Runtime/ui2/hooks.cs
-
50com.unity.uiwidgets/Runtime/ui2/isolate.cs
-
51com.unity.uiwidgets/Runtime/ui2/native_bindings.cs
-
313com.unity.uiwidgets/Runtime/ui2/painting.cs
-
17com.unity.uiwidgets/Runtime/ui2/window.cs
-
14engine/Build.bee.cs
-
14engine/src/flow/skia_gpu_object.cc
-
2engine/src/flow/skia_gpu_object.h
-
18engine/src/lib/ui/compositing/scene_builder.cc
-
6engine/src/lib/ui/painting/engine_layer.cc
-
15engine/src/lib/ui/painting/image.cc
-
2engine/src/lib/ui/painting/image.h
-
377engine/src/lib/ui/painting/image_decoder.cc
-
55engine/src/lib/ui/painting/image_decoder.h
-
42engine/src/lib/ui/painting/image_encoding.cc
-
14engine/src/lib/ui/painting/image_encoding.h
-
3engine/src/lib/ui/painting/picture.cc
-
14engine/src/lib/ui/window/platform_message_response_mono.cc
-
66engine/src/lib/ui/window/pointer_data.h
-
17engine/src/lib/ui/window/window.cc
-
41engine/src/render_api_d3d11.cc
-
60engine/src/runtime/mono_api.cc
-
1engine/src/runtime/mono_api.h
-
2engine/src/runtime/mono_isolate.cc
-
36engine/src/shell/common/shell.cc
-
16engine/src/shell/platform/embedder/embedder_task_runner.cc
-
3engine/src/shell/platform/embedder/embedder_task_runner.h
-
185engine/src/shell/platform/unity/uiwidgets_panel.cc
-
45engine/src/shell/platform/unity/uiwidgets_panel.h
-
7engine/src/shell/platform/unity/uiwidgets_system.h
-
6engine/src/shell/platform/unity/unity_surface_manager.h
-
3engine/third_party/Unity/IUnityUIWidgets.h
-
198engine/src/lib/ui/painting/codec.cc
-
46engine/src/lib/ui/painting/codec.h
-
22engine/src/lib/ui/painting/frame_info.cc
-
25engine/src/lib/ui/painting/frame_info.h
-
194engine/src/lib/ui/painting/multi_frame_codec.cc
-
69engine/src/lib/ui/painting/multi_frame_codec.h
-
110engine/src/lib/ui/painting/single_frame_codec.cc
-
40engine/src/lib/ui/painting/single_frame_codec.h
-
119engine/src/shell/platform/unity/unity_external_texture_gl.cc
-
46engine/src/shell/platform/unity/unity_external_texture_gl.h
|
|||
#pragma once |
|||
|
|||
#include "runtime/mono_api.h" |
|||
#include "runtime/mono_state.h" |
|||
typedef void (*EncodeImageCallback)(Mono_Handle callback_handle, |
|||
const uint8_t* data, size_t length); |
|||
typedef void (*RawEncodeImageCallback)(Mono_Handle callback_handle, |
|||
const uint8_t* data, size_t length); |
|||
|
|||
struct EncodeImageCallback { |
|||
std::weak_ptr<MonoState> mono_state; |
|||
RawEncodeImageCallback callback; |
|||
Mono_Handle callback_handle; |
|||
}; |
|||
EncodeImageCallback callback, |
|||
Mono_Handle callback_handle); |
|||
RawEncodeImageCallback callback, Mono_Handle callback_handle); |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "codec.h"
|
|||
|
|||
#include <variant>
|
|||
|
|||
#include "common/task_runners.h"
|
|||
#include "flutter/fml/logging.h"
|
|||
#include "flutter/fml/make_copyable.h"
|
|||
#include "flutter/fml/trace_event.h"
|
|||
#include "frame_info.h"
|
|||
#include "include/codec/SkCodec.h"
|
|||
#include "include/core/SkPixelRef.h"
|
|||
#include "multi_frame_codec.h"
|
|||
#include "single_frame_codec.h"
|
|||
|
|||
#if OS_ANDROID
|
|||
#include <sys/mman.h>
|
|||
#endif
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
namespace { |
|||
|
|||
// This must be kept in sync with the enum in painting.dart
|
|||
enum PixelFormat { |
|||
kRGBA8888, |
|||
kBGRA8888, |
|||
}; |
|||
|
|||
#if OS_ANDROID
|
|||
|
|||
// Compressed image buffers are allocated on the UI thread but are deleted on a
|
|||
// decoder worker thread. Android's implementation of malloc appears to
|
|||
// continue growing the native heap size when the allocating thread is
|
|||
// different from the freeing thread. To work around this, create an SkData
|
|||
// backed by an anonymous mapping.
|
|||
sk_sp<SkData> MakeSkDataWithCopy(const void* data, size_t length) { |
|||
if (length == 0) { |
|||
return SkData::MakeEmpty(); |
|||
} |
|||
|
|||
size_t mapping_length = length + sizeof(size_t); |
|||
void* mapping = ::mmap(nullptr, mapping_length, PROT_READ | PROT_WRITE, |
|||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); |
|||
|
|||
if (mapping == MAP_FAILED) { |
|||
return SkData::MakeEmpty(); |
|||
} |
|||
|
|||
*reinterpret_cast<size_t*>(mapping) = mapping_length; |
|||
void* mapping_data = reinterpret_cast<char*>(mapping) + sizeof(size_t); |
|||
::memcpy(mapping_data, data, length); |
|||
|
|||
SkData::ReleaseProc proc = [](const void* ptr, void* context) { |
|||
size_t* size_ptr = reinterpret_cast<size_t*>(context); |
|||
FML_DCHECK(ptr == size_ptr + 1); |
|||
if (::munmap(const_cast<void*>(context), *size_ptr) == -1) { |
|||
FML_LOG(ERROR) << "munmap of codec SkData failed"; |
|||
} |
|||
}; |
|||
|
|||
return SkData::MakeWithProc(mapping_data, length, proc, mapping); |
|||
} |
|||
|
|||
#else
|
|||
|
|||
sk_sp<SkData> MakeSkDataWithCopy(const void* data, size_t length) { |
|||
return SkData::MakeWithCopy(data, length); |
|||
} |
|||
|
|||
#endif // OS_ANDROID
|
|||
|
|||
} // anonymous namespace
|
|||
|
|||
static std::variant<ImageDecoder::ImageInfo, std::string> ConvertImageInfo( |
|||
Codec::_ImageInfo _image_info) { |
|||
PixelFormat pixel_format = static_cast<PixelFormat>(_image_info.format); |
|||
SkColorType color_type = kUnknown_SkColorType; |
|||
switch (pixel_format) { |
|||
case kRGBA8888: |
|||
color_type = kRGBA_8888_SkColorType; |
|||
break; |
|||
case kBGRA8888: |
|||
color_type = kBGRA_8888_SkColorType; |
|||
break; |
|||
} |
|||
if (color_type == kUnknown_SkColorType) { |
|||
return "Invalid pixel format"; |
|||
} |
|||
|
|||
int width = _image_info.width; |
|||
if (width <= 0) { |
|||
return "width must be greater than zero"; |
|||
} |
|||
int height = _image_info.height; |
|||
if (height <= 0) { |
|||
return "height must be greater than zero"; |
|||
} |
|||
|
|||
ImageDecoder::ImageInfo image_info; |
|||
image_info.sk_info = |
|||
SkImageInfo::Make(width, height, color_type, kPremul_SkAlphaType); |
|||
image_info.row_bytes = _image_info.rowBytes; |
|||
|
|||
if (image_info.row_bytes < image_info.sk_info.minRowBytes()) { |
|||
return "rowBytes does not match the width of the image"; |
|||
} |
|||
|
|||
return image_info; |
|||
} |
|||
|
|||
UIWIDGETS_API(const char*) |
|||
Codec_instantiateImageCodec(uint8_t* data, int data_length, |
|||
Codec::InstantiateImageCodecCallback callback, |
|||
Mono_Handle callback_handle, |
|||
Codec::_ImageInfo _image_info, bool has_image_info, |
|||
int target_width, int target_height) { |
|||
if (!callback || !callback_handle) { |
|||
return "Callback must be a function"; |
|||
} |
|||
|
|||
std::optional<ImageDecoder::ImageInfo> image_info; |
|||
|
|||
if (has_image_info) { |
|||
auto image_info_results = ConvertImageInfo(_image_info); |
|||
if (auto value = |
|||
std::get_if<ImageDecoder::ImageInfo>(&image_info_results)) { |
|||
image_info = *value; |
|||
} else if (auto error = std::get_if<std::string>(&image_info_results)) { |
|||
return error->c_str(); |
|||
} |
|||
} |
|||
|
|||
sk_sp<SkData> buffer = MakeSkDataWithCopy(data, data_length); |
|||
|
|||
if (image_info) { |
|||
const auto expected_size = |
|||
image_info->row_bytes * image_info->sk_info.height(); |
|||
if (buffer->size() < expected_size) { |
|||
return "Pixel buffer size does not match image size"; |
|||
} |
|||
} |
|||
|
|||
const int targetWidth = target_width; |
|||
const int targetHeight = target_height; |
|||
|
|||
std::unique_ptr<SkCodec> codec; |
|||
bool single_frame; |
|||
if (image_info) { |
|||
single_frame = true; |
|||
} else { |
|||
codec = SkCodec::MakeFromData(buffer); |
|||
if (!codec) { |
|||
return "Could not instantiate image codec."; |
|||
} |
|||
single_frame = codec->getFrameCount() == 1; |
|||
} |
|||
|
|||
fml::RefPtr<Codec> ui_codec; |
|||
|
|||
if (single_frame) { |
|||
ImageDecoder::ImageDescriptor descriptor; |
|||
descriptor.decompressed_image_info = image_info; |
|||
|
|||
if (targetWidth > 0) { |
|||
descriptor.target_width = targetWidth; |
|||
} |
|||
if (targetHeight > 0) { |
|||
descriptor.target_height = targetHeight; |
|||
} |
|||
descriptor.data = std::move(buffer); |
|||
|
|||
ui_codec = fml::MakeRefCounted<SingleFrameCodec>(std::move(descriptor)); |
|||
} else { |
|||
ui_codec = fml::MakeRefCounted<MultiFrameCodec>(std::move(codec)); |
|||
} |
|||
|
|||
ui_codec->AddRef(); |
|||
callback(callback_handle, ui_codec.get()); |
|||
return nullptr; |
|||
} |
|||
|
|||
void Codec::dispose() {} |
|||
|
|||
UIWIDGETS_API(void) Codec_dispose(Codec* ptr) { ptr->Release(); } |
|||
|
|||
UIWIDGETS_API(int) Codec_frameCount(Codec* ptr) { return ptr->frameCount(); } |
|||
|
|||
UIWIDGETS_API(int) Codec_repetitionCount(Codec* ptr) { |
|||
return ptr->repetitionCount(); |
|||
} |
|||
|
|||
UIWIDGETS_API(const char*) |
|||
Codec_getNextFrame(Codec* ptr, Codec::GetNextFrameCallback callback, |
|||
Mono_Handle callback_handle) { |
|||
return ptr->getNextFrame(callback, callback_handle); |
|||
} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include "frame_info.h" |
|||
#include "include/codec/SkCodec.h" |
|||
#include "include/core/SkBitmap.h" |
|||
#include "include/core/SkImage.h" |
|||
#include "runtime/mono_state.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class Codec : public fml::RefCountedThreadSafe<Codec> { |
|||
public: |
|||
virtual ~Codec() {} |
|||
|
|||
virtual int frameCount() const = 0; |
|||
|
|||
virtual int repetitionCount() const = 0; |
|||
|
|||
typedef void (*InstantiateImageCodecCallback)(Mono_Handle callback_handle, |
|||
Codec* codec); |
|||
|
|||
typedef void (*GetNextFrameCallback)(Mono_Handle callback_handle, |
|||
FrameInfo* frame_info); |
|||
|
|||
virtual const char* getNextFrame(GetNextFrameCallback callback, |
|||
Mono_Handle callback_handle) = 0; |
|||
|
|||
virtual size_t GetAllocationSize() { return 0; } |
|||
|
|||
void dispose(); |
|||
|
|||
struct _ImageInfo { |
|||
int width; |
|||
int height; |
|||
int format; |
|||
int rowBytes; |
|||
}; |
|||
|
|||
struct PendingCallback { |
|||
std::weak_ptr<MonoState> mono_state; |
|||
GetNextFrameCallback callback; |
|||
Mono_Handle callback_handle; |
|||
}; |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "frame_info.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
FrameInfo::FrameInfo(fml::RefPtr<CanvasImage> image, int durationMillis) |
|||
: image_(std::move(image)), durationMillis_(durationMillis) {} |
|||
|
|||
FrameInfo::~FrameInfo() {} |
|||
|
|||
UIWIDGETS_API(void) FrameInfo_dispose(FrameInfo* ptr) { ptr->Release(); } |
|||
|
|||
UIWIDGETS_API(int) FrameInfo_durationMillis(FrameInfo* ptr) { |
|||
return ptr->durationMillis(); |
|||
} |
|||
|
|||
UIWIDGETS_API(CanvasImage*) FrameInfo_image(FrameInfo* ptr) { |
|||
auto image = ptr->image(); |
|||
image->AddRef(); |
|||
return image.get(); |
|||
} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include "image.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
// A single animation frame. |
|||
class FrameInfo final : public fml::RefCountedThreadSafe<FrameInfo> { |
|||
public: |
|||
int durationMillis() { return durationMillis_; } |
|||
fml::RefPtr<CanvasImage> image() { return image_; } |
|||
|
|||
private: |
|||
FrameInfo(fml::RefPtr<CanvasImage> image, int durationMillis); |
|||
|
|||
~FrameInfo(); |
|||
|
|||
const fml::RefPtr<CanvasImage> image_; |
|||
const int durationMillis_; |
|||
|
|||
FML_FRIEND_MAKE_REF_COUNTED(FrameInfo); |
|||
FML_FRIEND_REF_COUNTED_THREAD_SAFE(FrameInfo); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "multi_frame_codec.h"
|
|||
|
|||
#include "flutter/fml/make_copyable.h"
|
|||
#include "include/core/SkPixelRef.h"
|
|||
#include "lib/ui/ui_mono_state.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
MultiFrameCodec::MultiFrameCodec(std::unique_ptr<SkCodec> codec) |
|||
: state_(new State(std::move(codec))) {} |
|||
|
|||
MultiFrameCodec::~MultiFrameCodec() = default; |
|||
|
|||
MultiFrameCodec::State::State(std::unique_ptr<SkCodec> codec) |
|||
: codec_(std::move(codec)), |
|||
frameCount_(codec_->getFrameCount()), |
|||
repetitionCount_(codec_->getRepetitionCount()), |
|||
nextFrameIndex_(0) {} |
|||
|
|||
static void InvokeNextFrameCallback( |
|||
fml::RefPtr<FrameInfo> frameInfo, |
|||
std::unique_ptr<Codec::PendingCallback> callback, size_t trace_id) { |
|||
std::shared_ptr<MonoState> mono_state = callback->mono_state.lock(); |
|||
if (!mono_state) { |
|||
FML_DLOG(ERROR) << "Could not acquire Mono state while attempting to fire " |
|||
"next frame callback."; |
|||
callback->callback(callback->callback_handle, nullptr); |
|||
return; |
|||
} |
|||
MonoState::Scope scope(mono_state); |
|||
if (!frameInfo) { |
|||
callback->callback(callback->callback_handle, nullptr); |
|||
} else { |
|||
frameInfo->AddRef(); |
|||
callback->callback(callback->callback_handle, frameInfo.get()); |
|||
} |
|||
} |
|||
|
|||
// Copied the source bitmap to the destination. If this cannot occur due to
|
|||
// running out of memory or the image info not being compatible, returns false.
|
|||
static bool CopyToBitmap(SkBitmap* dst, SkColorType dstColorType, |
|||
const SkBitmap& src) { |
|||
SkPixmap srcPM; |
|||
if (!src.peekPixels(&srcPM)) { |
|||
return false; |
|||
} |
|||
|
|||
SkBitmap tmpDst; |
|||
SkImageInfo dstInfo = srcPM.info().makeColorType(dstColorType); |
|||
if (!tmpDst.setInfo(dstInfo)) { |
|||
return false; |
|||
} |
|||
|
|||
if (!tmpDst.tryAllocPixels()) { |
|||
return false; |
|||
} |
|||
|
|||
SkPixmap dstPM; |
|||
if (!tmpDst.peekPixels(&dstPM)) { |
|||
return false; |
|||
} |
|||
|
|||
if (!srcPM.readPixels(dstPM)) { |
|||
return false; |
|||
} |
|||
|
|||
dst->swap(tmpDst); |
|||
return true; |
|||
} |
|||
|
|||
sk_sp<SkImage> MultiFrameCodec::State::GetNextFrameImage( |
|||
fml::WeakPtr<GrContext> resourceContext) { |
|||
SkBitmap bitmap = SkBitmap(); |
|||
SkImageInfo info = codec_->getInfo().makeColorType(kN32_SkColorType); |
|||
if (info.alphaType() == kUnpremul_SkAlphaType) { |
|||
info = info.makeAlphaType(kPremul_SkAlphaType); |
|||
} |
|||
bitmap.allocPixels(info); |
|||
|
|||
SkCodec::Options options; |
|||
options.fFrameIndex = nextFrameIndex_; |
|||
SkCodec::FrameInfo frameInfo; |
|||
codec_->getFrameInfo(nextFrameIndex_, &frameInfo); |
|||
const int requiredFrameIndex = frameInfo.fRequiredFrame; |
|||
if (requiredFrameIndex != SkCodec::kNoFrame) { |
|||
if (lastRequiredFrame_ == nullptr) { |
|||
FML_LOG(ERROR) << "Frame " << nextFrameIndex_ << " depends on frame " |
|||
<< requiredFrameIndex |
|||
<< " and no required frames are cached."; |
|||
return nullptr; |
|||
} else if (lastRequiredFrameIndex_ != requiredFrameIndex) { |
|||
FML_DLOG(INFO) << "Required frame " << requiredFrameIndex |
|||
<< " is not cached. Using " << lastRequiredFrameIndex_ |
|||
<< " instead"; |
|||
} |
|||
|
|||
if (lastRequiredFrame_->getPixels() && |
|||
CopyToBitmap(&bitmap, lastRequiredFrame_->colorType(), |
|||
*lastRequiredFrame_)) { |
|||
options.fPriorFrame = requiredFrameIndex; |
|||
} |
|||
} |
|||
|
|||
if (SkCodec::kSuccess != codec_->getPixels(info, bitmap.getPixels(), |
|||
bitmap.rowBytes(), &options)) { |
|||
FML_LOG(ERROR) << "Could not getPixels for frame " << nextFrameIndex_; |
|||
return nullptr; |
|||
} |
|||
|
|||
// Hold onto this if we need it to decode future frames.
|
|||
if (frameInfo.fDisposalMethod == SkCodecAnimation::DisposalMethod::kKeep) { |
|||
lastRequiredFrame_ = std::make_unique<SkBitmap>(bitmap); |
|||
lastRequiredFrameIndex_ = nextFrameIndex_; |
|||
} |
|||
|
|||
if (resourceContext) { |
|||
SkPixmap pixmap(bitmap.info(), bitmap.pixelRef()->pixels(), |
|||
bitmap.pixelRef()->rowBytes()); |
|||
return SkImage::MakeCrossContextFromPixmap(resourceContext.get(), pixmap, |
|||
true); |
|||
} else { |
|||
// Defer decoding until time of draw later on the raster thread. Can happen
|
|||
// when GL operations are currently forbidden such as in the background
|
|||
// on iOS.
|
|||
return SkImage::MakeFromBitmap(bitmap); |
|||
} |
|||
} |
|||
|
|||
void MultiFrameCodec::State::GetNextFrameAndInvokeCallback( |
|||
std::unique_ptr<PendingCallback> callback, |
|||
fml::RefPtr<fml::TaskRunner> ui_task_runner, |
|||
fml::WeakPtr<GrContext> resourceContext, |
|||
fml::RefPtr<SkiaUnrefQueue> unref_queue, size_t trace_id) { |
|||
fml::RefPtr<FrameInfo> frameInfo = NULL; |
|||
sk_sp<SkImage> skImage = GetNextFrameImage(resourceContext); |
|||
if (skImage) { |
|||
fml::RefPtr<CanvasImage> image = CanvasImage::Create(); |
|||
image->set_image({skImage, std::move(unref_queue)}); |
|||
SkCodec::FrameInfo skFrameInfo; |
|||
codec_->getFrameInfo(nextFrameIndex_, &skFrameInfo); |
|||
frameInfo = |
|||
fml::MakeRefCounted<FrameInfo>(std::move(image), skFrameInfo.fDuration); |
|||
} |
|||
nextFrameIndex_ = (nextFrameIndex_ + 1) % frameCount_; |
|||
|
|||
ui_task_runner->PostTask(fml::MakeCopyable( |
|||
[callback = std::move(callback), frameInfo, trace_id]() mutable { |
|||
InvokeNextFrameCallback(frameInfo, std::move(callback), trace_id); |
|||
})); |
|||
} |
|||
|
|||
const char* MultiFrameCodec::getNextFrame(GetNextFrameCallback callback, |
|||
Mono_Handle callback_handle) { |
|||
static size_t trace_counter = 1; |
|||
const size_t trace_id = trace_counter++; |
|||
|
|||
if (!callback || !callback_handle) { |
|||
return "Callback must be a function"; |
|||
} |
|||
|
|||
auto* mono_state = UIMonoState::Current(); |
|||
|
|||
const auto& task_runners = mono_state->GetTaskRunners(); |
|||
|
|||
task_runners.GetIOTaskRunner()->PostTask(fml::MakeCopyable( |
|||
[callback = std::make_unique<PendingCallback>(PendingCallback{ |
|||
MonoState::Current()->GetWeakPtr(), callback, callback_handle}), |
|||
weak_state = std::weak_ptr<MultiFrameCodec::State>(state_), trace_id, |
|||
ui_task_runner = task_runners.GetUITaskRunner(), |
|||
io_manager = mono_state->GetIOManager()]() mutable { |
|||
auto state = weak_state.lock(); |
|||
if (!state) { |
|||
ui_task_runner->PostTask( |
|||
fml::MakeCopyable([callback = std::move(callback)]() { |
|||
callback->callback(callback->callback_handle, nullptr); |
|||
})); |
|||
return; |
|||
} |
|||
state->GetNextFrameAndInvokeCallback( |
|||
std::move(callback), std::move(ui_task_runner), |
|||
io_manager->GetResourceContext(), io_manager->GetSkiaUnrefQueue(), |
|||
trace_id); |
|||
})); |
|||
|
|||
return nullptr; |
|||
} |
|||
|
|||
int MultiFrameCodec::frameCount() const { return state_->frameCount_; } |
|||
|
|||
int MultiFrameCodec::repetitionCount() const { |
|||
return state_->repetitionCount_; |
|||
} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include "codec.h" |
|||
#include "flutter/fml/macros.h" |
|||
#include "runtime/mono_state.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class MultiFrameCodec : public Codec { |
|||
public: |
|||
MultiFrameCodec(std::unique_ptr<SkCodec> codec); |
|||
|
|||
~MultiFrameCodec() override; |
|||
|
|||
// |Codec| |
|||
int frameCount() const override; |
|||
|
|||
// |Codec| |
|||
int repetitionCount() const override; |
|||
|
|||
// |Codec| |
|||
const char* getNextFrame(GetNextFrameCallback callback, |
|||
Mono_Handle callback_handle) override; |
|||
|
|||
private: |
|||
|
|||
// Captures the state shared between the IO and UI task runners. |
|||
// |
|||
// The state is initialized on the UI task runner when the Dart object is |
|||
// created. Decoding occurs on the IO task runner. Since it is possible for |
|||
// the UI object to be collected independently of the IO task runner work, |
|||
// it is not safe for this state to live directly on the MultiFrameCodec. |
|||
// Instead, the MultiFrameCodec creates this object when it is constructed, |
|||
// shares it with the IO task runner's decoding work, and sets the live_ |
|||
// member to false when it is destructed. |
|||
struct State { |
|||
State(std::unique_ptr<SkCodec> codec); |
|||
|
|||
const std::unique_ptr<SkCodec> codec_; |
|||
const int frameCount_; |
|||
const int repetitionCount_; |
|||
|
|||
// The non-const members and functions below here are only read or written |
|||
// to on the IO thread. They are not safe to access or write on the UI |
|||
// thread. |
|||
int nextFrameIndex_; |
|||
// The last decoded frame that's required to decode any subsequent frames. |
|||
std::unique_ptr<SkBitmap> lastRequiredFrame_; |
|||
|
|||
// The index of the last decoded required frame. |
|||
int lastRequiredFrameIndex_ = -1; |
|||
|
|||
sk_sp<SkImage> GetNextFrameImage(fml::WeakPtr<GrContext> resourceContext); |
|||
|
|||
void GetNextFrameAndInvokeCallback( |
|||
std::unique_ptr<PendingCallback> callback, |
|||
fml::RefPtr<fml::TaskRunner> ui_task_runner, |
|||
fml::WeakPtr<GrContext> resourceContext, |
|||
fml::RefPtr<SkiaUnrefQueue> unref_queue, size_t trace_id); |
|||
}; |
|||
|
|||
// Shared across the UI and IO task runners. |
|||
std::shared_ptr<State> state_; |
|||
|
|||
FML_FRIEND_MAKE_REF_COUNTED(MultiFrameCodec); |
|||
FML_FRIEND_REF_COUNTED_THREAD_SAFE(MultiFrameCodec); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "single_frame_codec.h"
|
|||
|
|||
#include "frame_info.h"
|
|||
#include "lib/ui/ui_mono_state.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
SingleFrameCodec::SingleFrameCodec(ImageDecoder::ImageDescriptor descriptor) |
|||
: status_(Status::kNew), descriptor_(std::move(descriptor)) {} |
|||
|
|||
SingleFrameCodec::~SingleFrameCodec() = default; |
|||
|
|||
int SingleFrameCodec::frameCount() const { return 1; } |
|||
|
|||
int SingleFrameCodec::repetitionCount() const { return 0; } |
|||
|
|||
const char* SingleFrameCodec::getNextFrame(GetNextFrameCallback callback, |
|||
Mono_Handle callback_handle) { |
|||
if (!callback || !callback_handle) { |
|||
return "Callback must be a function"; |
|||
} |
|||
|
|||
if (status_ == Status::kComplete) { |
|||
cached_frame_->AddRef(); |
|||
callback(callback_handle, cached_frame_.get()); |
|||
return nullptr; |
|||
} |
|||
|
|||
// This has to be valid because this method is called from Dart.
|
|||
auto* mono_state = UIMonoState::Current(); |
|||
|
|||
pending_callbacks_.emplace_back(PendingCallback{mono_state->GetWeakPtr(), callback, callback_handle}); |
|||
|
|||
if (status_ == Status::kInProgress) { |
|||
// Another call to getNextFrame is in progress and will invoke the
|
|||
// pending callbacks when decoding completes.
|
|||
return nullptr; |
|||
} |
|||
|
|||
auto decoder = mono_state->GetImageDecoder(); |
|||
|
|||
if (!decoder) { |
|||
return "Image decoder not available."; |
|||
} |
|||
|
|||
// The SingleFrameCodec must be deleted on the UI thread. Allocate a RefPtr
|
|||
// on the heap to ensure that the SingleFrameCodec remains alive until the
|
|||
// decoder callback is invoked on the UI thread. The callback can then
|
|||
// drop the reference.
|
|||
fml::RefPtr<SingleFrameCodec>* raw_codec_ref = |
|||
new fml::RefPtr<SingleFrameCodec>(this); |
|||
|
|||
decoder->Decode(descriptor_, [raw_codec_ref](auto image) { |
|||
std::unique_ptr<fml::RefPtr<SingleFrameCodec>> codec_ref(raw_codec_ref); |
|||
fml::RefPtr<SingleFrameCodec> codec(std::move(*codec_ref)); |
|||
|
|||
auto state = codec->pending_callbacks_.front().mono_state.lock(); |
|||
|
|||
if (!state) { |
|||
// This is probably because the isolate has been terminated before the
|
|||
// image could be decoded.
|
|||
|
|||
for (const auto& entry : codec->pending_callbacks_) { |
|||
entry.callback(entry.callback_handle, nullptr); |
|||
} |
|||
codec->pending_callbacks_.clear(); |
|||
return; |
|||
} |
|||
|
|||
MonoState::Scope scope(state.get()); |
|||
|
|||
if (image.get()) { |
|||
auto canvas_image = fml::MakeRefCounted<CanvasImage>(); |
|||
canvas_image->set_image(std::move(image)); |
|||
|
|||
codec->cached_frame_ = fml::MakeRefCounted<FrameInfo>( |
|||
std::move(canvas_image), 0 /* duration */); |
|||
} |
|||
|
|||
// The cached frame is now available and should be returned to any future
|
|||
// callers.
|
|||
codec->status_ = Status::kComplete; |
|||
|
|||
// Invoke any callbacks that were provided before the frame was decoded.
|
|||
for (const auto& entry : codec->pending_callbacks_) { |
|||
codec->cached_frame_->AddRef(); |
|||
entry.callback(entry.callback_handle, codec->cached_frame_.get()); |
|||
} |
|||
codec->pending_callbacks_.clear(); |
|||
}); |
|||
|
|||
// The encoded data is no longer needed now that it has been handed off
|
|||
// to the decoder.
|
|||
descriptor_.data.reset(); |
|||
|
|||
status_ = Status::kInProgress; |
|||
|
|||
return nullptr; |
|||
} |
|||
|
|||
size_t SingleFrameCodec::GetAllocationSize() { |
|||
const auto& data = descriptor_.data; |
|||
const auto data_byte_size = data ? data->size() : 0; |
|||
const auto frame_byte_size = (cached_frame_ && cached_frame_->image()) |
|||
? cached_frame_->image()->GetAllocationSize() |
|||
: 0; |
|||
return data_byte_size + frame_byte_size + sizeof(this); |
|||
} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include "codec.h" |
|||
#include "flutter/fml/macros.h" |
|||
#include "frame_info.h" |
|||
#include "image_decoder.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class SingleFrameCodec : public Codec { |
|||
public: |
|||
SingleFrameCodec(ImageDecoder::ImageDescriptor descriptor); |
|||
|
|||
~SingleFrameCodec() override; |
|||
|
|||
// |Codec| |
|||
int frameCount() const override; |
|||
|
|||
// |Codec| |
|||
int repetitionCount() const override; |
|||
|
|||
// |Codec| |
|||
const char* getNextFrame(GetNextFrameCallback callback, |
|||
Mono_Handle callback_handle) override; |
|||
|
|||
size_t GetAllocationSize() override; |
|||
|
|||
private: |
|||
enum class Status { kNew, kInProgress, kComplete }; |
|||
Status status_; |
|||
ImageDecoder::ImageDescriptor descriptor_; |
|||
fml::RefPtr<FrameInfo> cached_frame_; |
|||
|
|||
std::vector<PendingCallback> pending_callbacks_; |
|||
|
|||
FML_FRIEND_MAKE_REF_COUNTED(SingleFrameCodec); |
|||
FML_FRIEND_REF_COUNTED_THREAD_SAFE(SingleFrameCodec); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
|
|||
#include "unity_external_texture_gl.h"
|
|||
|
|||
#include <EGL/egl.h>
|
|||
#include <EGL/eglext.h>
|
|||
#include <EGL/eglext_angle.h>
|
|||
#include <GLES2/gl2.h>
|
|||
#include <GLES2/gl2ext.h>
|
|||
#include <d3d11.h>
|
|||
|
|||
#include "flutter/fml/logging.h"
|
|||
#include "include/gpu/GrBackendSurface.h"
|
|||
#include "include/gpu/GrContext.h"
|
|||
#include "include/gpu/gl/GrGLTypes.h"
|
|||
#include "src/gpu/gl/GrGLDefines.h"
|
|||
#include "uiwidgets_system.h"
|
|||
|
|||
namespace uiwidgets { |
|||
|
|||
UnityExternalTextureGL::UnityExternalTextureGL( |
|||
int64_t texture_identifier, void* native_texture_ptr, |
|||
UnitySurfaceManager* unity_surface_manager) |
|||
: Texture(texture_identifier), |
|||
unity_surface_manager_(unity_surface_manager) { |
|||
auto* graphics = UIWidgetsSystem::GetInstancePtr() |
|||
->GetUnityInterfaces() |
|||
->Get<IUnityGraphics>(); |
|||
FML_DCHECK(graphics->GetRenderer() == kUnityGfxRendererD3D11); |
|||
|
|||
auto* src_d3d11_texture = static_cast<ID3D11Texture2D*>(native_texture_ptr); |
|||
|
|||
IDXGIResource* src_d3d11_resource; |
|||
HRESULT hr = src_d3d11_texture->QueryInterface( |
|||
__uuidof(IDXGIResource), reinterpret_cast<void**>(&src_d3d11_resource)); |
|||
|
|||
FML_CHECK(SUCCEEDED(hr)); |
|||
|
|||
HANDLE shared_image_handle; |
|||
hr = src_d3d11_resource->GetSharedHandle(&shared_image_handle); |
|||
FML_CHECK(SUCCEEDED(hr)); |
|||
|
|||
src_d3d11_resource->Release(); |
|||
|
|||
IDXGIResource* d3d11_resource; |
|||
|
|||
unity_surface_manager_->GetD3D11Device()->OpenSharedResource( |
|||
shared_image_handle, __uuidof(ID3D11Resource), |
|||
reinterpret_cast<void**>(&d3d11_resource)); |
|||
|
|||
d3d11_resource->QueryInterface(__uuidof(ID3D11Texture2D), |
|||
reinterpret_cast<void**>(&d3d11_texture_)); |
|||
|
|||
d3d11_resource->Release(); |
|||
|
|||
const EGLint attribs[] = {EGL_NONE}; |
|||
|
|||
egl_image_ = |
|||
eglCreateImageKHR(unity_surface_manager_->GetEGLDisplay(), EGL_NO_CONTEXT, |
|||
EGL_D3D11_TEXTURE_ANGLE, |
|||
static_cast<EGLClientBuffer>(d3d11_texture_), attribs); |
|||
|
|||
gl_texture_ = 0; |
|||
} |
|||
|
|||
UnityExternalTextureGL::~UnityExternalTextureGL() { |
|||
last_image_ = nullptr; |
|||
if (gl_texture_) { |
|||
glDeleteTextures(1, &gl_texture_); |
|||
gl_texture_ = 0; |
|||
} |
|||
|
|||
eglDestroyImageKHR(unity_surface_manager_->GetEGLDisplay(), egl_image_); |
|||
d3d11_texture_->Release(); |
|||
} |
|||
|
|||
// |flutter::Texture|
|
|||
void UnityExternalTextureGL::Paint(SkCanvas& canvas, const SkRect& bounds, |
|||
bool freeze, GrContext* context) { |
|||
if (!last_image_) { |
|||
if (!gl_texture_) { |
|||
glGenTextures(1, &gl_texture_); |
|||
glBindTexture(GL_TEXTURE_2D, gl_texture_); |
|||
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image_); |
|||
} |
|||
|
|||
GrGLTextureInfo texture_info; |
|||
texture_info.fTarget = GR_GL_TEXTURE_2D; |
|||
texture_info.fID = gl_texture_; |
|||
texture_info.fFormat = GR_GL_RGBA8; |
|||
|
|||
GrBackendTexture backend_tex = GrBackendTexture( |
|||
bounds.width(), bounds.height(), GrMipMapped::kNo, texture_info); |
|||
|
|||
last_image_ = SkImage::MakeFromTexture( |
|||
context, backend_tex, kBottomLeft_GrSurfaceOrigin, |
|||
kRGBA_8888_SkColorType, kOpaque_SkAlphaType, nullptr); |
|||
} |
|||
|
|||
if (last_image_) { |
|||
if (bounds != SkRect::Make(last_image_->bounds())) { |
|||
canvas.drawImageRect(last_image_, bounds, nullptr); |
|||
} else { |
|||
canvas.drawImage(last_image_, bounds.x(), bounds.y()); |
|||
} |
|||
} |
|||
} |
|||
|
|||
// |flutter::Texture|
|
|||
void UnityExternalTextureGL::OnGrContextCreated() {} |
|||
|
|||
// |flutter::Texture|
|
|||
void UnityExternalTextureGL::OnGrContextDestroyed() {} |
|||
|
|||
// |flutter::Texture|
|
|||
void UnityExternalTextureGL::MarkNewFrameAvailable() {} |
|||
|
|||
// |flutter::Texture|
|
|||
void UnityExternalTextureGL::OnTextureUnregistered() {} |
|||
|
|||
} // namespace uiwidgets
|
|
|||
#pragma once |
|||
|
|||
#include "flow/texture.h" |
|||
#include "flutter/fml/macros.h" |
|||
#include "include/core/SkImage.h" |
|||
#include "include/core/SkSize.h" |
|||
#include "unity_surface_manager.h" |
|||
|
|||
namespace uiwidgets { |
|||
|
|||
class UnityExternalTextureGL : public Texture { |
|||
public: |
|||
UnityExternalTextureGL(int64_t texture_identifier, void* native_texture_ptr, |
|||
UnitySurfaceManager* unity_surface_manager); |
|||
|
|||
~UnityExternalTextureGL() override; |
|||
|
|||
private: |
|||
UnitySurfaceManager* unity_surface_manager_; |
|||
bool gr_context_created_ = false; |
|||
|
|||
ID3D11Texture2D* d3d11_texture_; |
|||
EGLImage egl_image_; |
|||
GLuint gl_texture_; |
|||
sk_sp<SkImage> last_image_; |
|||
|
|||
// |flutter::Texture| |
|||
void Paint(SkCanvas& canvas, const SkRect& bounds, bool freeze, |
|||
GrContext* context) override; |
|||
|
|||
// |flutter::Texture| |
|||
void OnGrContextCreated() override; |
|||
|
|||
// |flutter::Texture| |
|||
void OnGrContextDestroyed() override; |
|||
|
|||
// |flutter::Texture| |
|||
void MarkNewFrameAvailable() override; |
|||
|
|||
// |flutter::Texture| |
|||
void OnTextureUnregistered() override; |
|||
|
|||
FML_DISALLOW_COPY_AND_ASSIGN(UnityExternalTextureGL); |
|||
}; |
|||
|
|||
} // namespace uiwidgets |
撰写
预览
正在加载...
取消
保存
Reference in new issue