Remove deprecated Stream APIs
This commit is contained in:
committed by
Mathias Agopian
parent
68da1a25eb
commit
dab02e915e
@@ -7,6 +7,8 @@ A new header is inserted each time a *tag* is created.
|
||||
|
||||
## v1.21.2
|
||||
|
||||
- remove deprecated `Stream` APIs, see `Texture::import()` for an alternative [⚠️ **API Change**].
|
||||
|
||||
## v1.21.1
|
||||
|
||||
- engine: Allow both screen-space refraction and screen-space reflections on the same object [⚠️ **Material breakage**].
|
||||
|
||||
@@ -98,16 +98,6 @@ Java_com_google_android_filament_Stream_nBuilderStreamSource(JNIEnv* env,
|
||||
builder->setStreamSource(env, streamSource);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Stream_nBuilderStream(JNIEnv*, jclass,
|
||||
jlong nativeStreamBuilder, jlong externalTextureId) {
|
||||
StreamBuilder* builder = (StreamBuilder*) nativeStreamBuilder;
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
builder->builder()->stream(externalTextureId);
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_Stream_nBuilderWidth(JNIEnv*, jclass,
|
||||
jlong nativeStreamBuilder, jint width) {
|
||||
@@ -143,41 +133,6 @@ Java_com_google_android_filament_Stream_nSetDimensions(JNIEnv*, jclass, jlong na
|
||||
stream->setDimensions((uint32_t) width, (uint32_t) height);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_Stream_nReadPixels(JNIEnv *env, jclass,
|
||||
jlong nativeStream, jlong nativeEngine,
|
||||
jint xoffset, jint yoffset, jint width, jint height,
|
||||
jobject storage, jint remaining,
|
||||
jint left, jint top, jint type, jint alignment, jint stride, jint format,
|
||||
jobject handler, jobject runnable) {
|
||||
Stream *stream = (Stream *) nativeStream;
|
||||
Engine *engine = (Engine *) nativeEngine;
|
||||
|
||||
stride = stride ? stride : width;
|
||||
size_t sizeInBytes = PixelBufferDescriptor::computeDataSize(
|
||||
(PixelDataFormat) format, (PixelDataType) type,
|
||||
(size_t) stride, (size_t) (height + top), (size_t) alignment);
|
||||
|
||||
AutoBuffer nioBuffer(env, storage, 0);
|
||||
if (sizeInBytes > (remaining << nioBuffer.getShift())) {
|
||||
// BufferOverflowException
|
||||
return -1;
|
||||
}
|
||||
|
||||
void *buffer = nioBuffer.getData();
|
||||
auto *callback = JniBufferCallback::make(engine, env, handler, runnable, std::move(nioBuffer));
|
||||
|
||||
PixelBufferDescriptor desc(buffer, sizeInBytes, (backend::PixelDataFormat) format,
|
||||
(backend::PixelDataType) type, (uint8_t) alignment, (uint32_t) left, (uint32_t) top,
|
||||
(uint32_t) stride,
|
||||
callback->getHandler(), &JniBufferCallback::postToJavaAndDestroy, callback);
|
||||
|
||||
stream->readPixels(uint32_t(xoffset), uint32_t(yoffset), uint32_t(width), uint32_t(height),
|
||||
std::move(desc));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_com_google_android_filament_Stream_nGetTimestamp(JNIEnv*, jclass, jlong nativeStream) {
|
||||
Stream *stream = (Stream *) nativeStream;
|
||||
|
||||
@@ -103,9 +103,6 @@ public class Stream {
|
||||
/** Not synchronized but copy-free. Good for video. */
|
||||
NATIVE,
|
||||
|
||||
/** Synchronized, but GL-only and incurs copies. Good for AR on devices before API 26. */
|
||||
TEXTURE_ID,
|
||||
|
||||
/** Synchronized, copy-free, and take a release callback. Good for AR but requires API 26+. */
|
||||
ACQUIRED,
|
||||
};
|
||||
@@ -121,7 +118,7 @@ public class Stream {
|
||||
* By default, Stream objects are {@link StreamType#ACQUIRED ACQUIRED} and must have external images pushed to them via
|
||||
* {@link #setAcquiredImage}.
|
||||
*
|
||||
* To create a {@link StreamType#NATIVE NATIVE} or {@link StreamType#TEXTURE_ID TEXTURE_ID} stream, call one of the <pre>stream</pre> methods
|
||||
* To create a {@link StreamType#NATIVE NATIVE} stream, call one of the <pre>stream</pre> methods
|
||||
* on the builder.
|
||||
*/
|
||||
public static class Builder {
|
||||
@@ -156,27 +153,6 @@ public class Stream {
|
||||
throw new IllegalArgumentException("Invalid stream source: " + streamSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link StreamType#TEXTURE_ID TEXTURE_ID} stream. A copy stream will sample data from the supplied
|
||||
* external texture and copy it into an internal private texture.
|
||||
*
|
||||
* <p>Currently only OpenGL external texture ids are supported.</p>
|
||||
*
|
||||
* @param externalTextureId An opaque texture id (typically a GLuint created with
|
||||
* <code>glGenTextures()</code>) in a context shared with
|
||||
* filament -- in that case this texture's target must be
|
||||
* <code>GL_TEXTURE_EXTERNAL_OES.</code>
|
||||
* @return This Builder, for chaining calls.
|
||||
* @see Texture#setExternalStream
|
||||
* @deprecated this method existed only for ARCore which doesn't need this anymore, use {@link Texture.Builder#importTexture(long)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
@NonNull
|
||||
public Builder stream(long externalTextureId) {
|
||||
nBuilderStream(mNativeBuilder, externalTextureId);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param width initial width of the incoming stream. Whether this value is used is
|
||||
* stream dependent. On Android, it must be set when using
|
||||
@@ -276,92 +252,6 @@ public class Stream {
|
||||
nSetDimensions(getNativeObject(), width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads back the content of the last frame of a <code>Stream</code> since the last call to
|
||||
* {@link Renderer#beginFrame}.
|
||||
*
|
||||
* <p>The Stream must be a copy stream, which can be checked with {@link #getStreamType()}.
|
||||
* This function is a no-op otherwise.</p>
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* Stream buffer User buffer (PixelBufferDescriptor)
|
||||
* +--------------------+
|
||||
* | | .stride .alignment
|
||||
* | | ----------------------->-->
|
||||
* | | O----------------------+--+ low addresses
|
||||
* | | | | | |
|
||||
* | w | | | .top | |
|
||||
* | <---------> | | V | |
|
||||
* | +---------+ | | +---------+ | |
|
||||
* | | ^ | | ======> | | | | |
|
||||
* | x | h| | | |.left| | | |
|
||||
* +------>| v | | +---->| | | |
|
||||
* | +.........+ | | +.........+ | |
|
||||
* | ^ | | | |
|
||||
* | y | | +----------------------+--+ high addresses
|
||||
* O------------+-------+
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* <p>Typically readPixels() will be called after {@link Renderer#beginFrame}.</p>
|
||||
*
|
||||
* <p>After calling this method, the callback associated with <code>buffer</code>
|
||||
* will be invoked on the main thread, indicating that the read-back has completed.
|
||||
* Typically, this will happen after multiple calls to {@link Renderer#beginFrame},
|
||||
* {@link Renderer#render}, {@link Renderer#endFrame}.</p>
|
||||
*
|
||||
* <p><code>readPixels</code> is intended for debugging and testing.
|
||||
* It will impact performance significantly.</p>
|
||||
*
|
||||
* @param xoffset left offset of the sub-region to read back
|
||||
* @param yoffset bottom offset of the sub-region to read back
|
||||
* @param width width of the sub-region to read back
|
||||
* @param height height of the sub-region to read back
|
||||
* @param buffer client-side buffer where the read-back will be written
|
||||
*
|
||||
* <p>
|
||||
* The following format are always supported:
|
||||
* <li>{@link Texture.Format#RGBA}</li>
|
||||
* <li>{@link Texture.Format#RGBA_INTEGER}</li>
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The following types are always supported:
|
||||
* <li>{@link Texture.Type#UBYTE}</li>
|
||||
* <li>{@link Texture.Type#UINT}</li>
|
||||
* <li>{@link Texture.Type#INT}</li>
|
||||
* <li>{@link Texture.Type#FLOAT}</li>
|
||||
* </p>
|
||||
*
|
||||
* <p>Other combination of format/type may be supported. If a combination is
|
||||
* not supported, this operation may fail silently. Use a DEBUG build
|
||||
* to get some logs about the failure.</p>
|
||||
*
|
||||
* @exception BufferOverflowException if the specified parameters would result in reading
|
||||
* outside of <code>buffer</code>.
|
||||
*/
|
||||
public void readPixels(
|
||||
@IntRange(from = 0) int xoffset, @IntRange(from = 0) int yoffset,
|
||||
@IntRange(from = 0) int width, @IntRange(from = 0) int height,
|
||||
@NonNull Texture.PixelBufferDescriptor buffer) {
|
||||
|
||||
if (buffer.storage.isReadOnly()) {
|
||||
throw new ReadOnlyBufferException();
|
||||
}
|
||||
|
||||
int result = nReadPixels(getNativeObject(), mNativeEngine,
|
||||
xoffset, yoffset, width, height,
|
||||
buffer.storage, buffer.storage.remaining(),
|
||||
buffer.left, buffer.top, buffer.type.ordinal(), buffer.alignment,
|
||||
buffer.stride, buffer.format.ordinal(),
|
||||
buffer.handler, buffer.callback);
|
||||
|
||||
if (result < 0) {
|
||||
throw new BufferOverflowException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the presentation time of the currently displayed frame in nanosecond.
|
||||
*
|
||||
@@ -387,7 +277,6 @@ public class Stream {
|
||||
private static native long nCreateBuilder();
|
||||
private static native void nDestroyBuilder(long nativeStreamBuilder);
|
||||
private static native void nBuilderStreamSource(long nativeStreamBuilder, Object streamSource);
|
||||
private static native void nBuilderStream(long nativeStreamBuilder, long externalTextureId);
|
||||
private static native void nBuilderWidth(long nativeStreamBuilder, int width);
|
||||
private static native void nBuilderHeight(long nativeStreamBuilder, int height);
|
||||
private static native long nBuilderBuild(long nativeStreamBuilder, long nativeEngine);
|
||||
|
||||
+1
-32
@@ -79,8 +79,6 @@ class MainActivity : Activity(), ActivityCompat.OnRequestPermissionsResultCallba
|
||||
// Performs the rendering and schedules new frames
|
||||
private val frameScheduler = FrameCallback()
|
||||
|
||||
private var externalTextureID: Int = 0
|
||||
|
||||
@RequiresApi(30)
|
||||
class Api30Impl {
|
||||
companion object {
|
||||
@@ -103,8 +101,6 @@ class MainActivity : Activity(), ActivityCompat.OnRequestPermissionsResultCallba
|
||||
setupView()
|
||||
setupScene()
|
||||
|
||||
externalTextureID = createExternalTexture()
|
||||
|
||||
@Suppress("deprecation")
|
||||
val display = if (Build.VERSION.SDK_INT >= 30) {
|
||||
Api30Impl.getDisplay(this)
|
||||
@@ -112,7 +108,7 @@ class MainActivity : Activity(), ActivityCompat.OnRequestPermissionsResultCallba
|
||||
windowManager.defaultDisplay!!
|
||||
}
|
||||
|
||||
streamHelper = StreamHelper(engine, materialInstance, display, externalTextureID)
|
||||
streamHelper = StreamHelper(engine, materialInstance, display)
|
||||
this.title = streamHelper.getTestName()
|
||||
}
|
||||
|
||||
@@ -445,31 +441,4 @@ class MainActivity : Activity(), ActivityCompat.OnRequestPermissionsResultCallba
|
||||
check(EGL14.eglMakeCurrent(display, surface, surface, context)) { "Error making GL context." }
|
||||
return context
|
||||
}
|
||||
|
||||
private fun createExternalTexture(): Int {
|
||||
val textures = IntArray(1)
|
||||
GLES30.glGenTextures(1, textures, 0)
|
||||
val result = textures[0]
|
||||
|
||||
val textureTarget = GLES11Ext.GL_TEXTURE_EXTERNAL_OES
|
||||
GLES30.glBindTexture(textureTarget, result)
|
||||
GLES30.glTexParameteri(textureTarget, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE)
|
||||
GLES30.glTexParameteri(textureTarget, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE)
|
||||
GLES30.glTexParameteri(textureTarget, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_NEAREST)
|
||||
GLES30.glTexParameteri(textureTarget, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_NEAREST)
|
||||
|
||||
if (!GLES30.glIsTexture(result)) {
|
||||
throw RuntimeException("OpenGL error: $result is an invalid texture.")
|
||||
}
|
||||
|
||||
val error = GLES30.glGetError()
|
||||
if (error != GLES30.GL_NO_ERROR) {
|
||||
val errorString = GLU.gluErrorString(error)
|
||||
throw RuntimeException("OpenGL error: $errorString!")
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+1
-24
@@ -37,7 +37,6 @@ class StreamHelper(
|
||||
private val filamentEngine: Engine,
|
||||
private val filamentMaterial: MaterialInstance,
|
||||
private val display: Display,
|
||||
private val externalTextureId: Int
|
||||
) {
|
||||
/**
|
||||
* The StreamSource configures the source data for the texture.
|
||||
@@ -51,7 +50,6 @@ class StreamHelper(
|
||||
*/
|
||||
enum class StreamSource {
|
||||
CANVAS_STREAM_NATIVE, // copy-free but does not guarantee synchronization
|
||||
CANVAS_STREAM_TEXID, // synchronized but incurs a copy
|
||||
CANVAS_STREAM_ACQUIRED, // synchronized and copy-free
|
||||
}
|
||||
|
||||
@@ -127,10 +125,6 @@ class StreamHelper(
|
||||
|
||||
surface.unlockCanvasAndPost(canvas)
|
||||
|
||||
if (streamSource == StreamSource.CANVAS_STREAM_TEXID) {
|
||||
surfaceTexture!!.updateTexImage()
|
||||
}
|
||||
|
||||
if (streamSource == StreamSource.CANVAS_STREAM_ACQUIRED) {
|
||||
val image = imageReader!!.acquireLatestImage()
|
||||
filamentStream!!.setAcquiredImage(
|
||||
@@ -146,7 +140,7 @@ class StreamHelper(
|
||||
|
||||
fun nextTest() {
|
||||
stopTest()
|
||||
streamSource = StreamSource.values()[(streamSource.ordinal + 1) % 3]
|
||||
streamSource = StreamSource.values()[(streamSource.ordinal + 1) % StreamSource.values().size]
|
||||
startTest()
|
||||
}
|
||||
|
||||
@@ -213,23 +207,6 @@ class StreamHelper(
|
||||
filamentTexture.setExternalStream(filamentEngine, filamentStream!!)
|
||||
}
|
||||
|
||||
if (streamSource == StreamSource.CANVAS_STREAM_TEXID) {
|
||||
|
||||
// Create the Android surface that will hold the canvas image.
|
||||
surfaceTexture = SurfaceTexture(externalTextureId)
|
||||
surfaceTexture!!.setDefaultBufferSize(resolution.width, resolution.height)
|
||||
canvasSurface = Surface(surfaceTexture)
|
||||
|
||||
// Create the Filament Stream object that gets bound to the Texture.
|
||||
filamentStream = Stream.Builder()
|
||||
.stream(externalTextureId.toLong())
|
||||
.width(resolution.width)
|
||||
.height(resolution.height)
|
||||
.build(filamentEngine)
|
||||
|
||||
filamentTexture.setExternalStream(filamentEngine, filamentStream!!)
|
||||
}
|
||||
|
||||
if (streamSource == StreamSource.CANVAS_STREAM_ACQUIRED) {
|
||||
filamentStream = Stream.Builder()
|
||||
.width(resolution.width)
|
||||
|
||||
@@ -65,8 +65,6 @@ if (FILAMENT_SUPPORTS_OPENGL AND NOT FILAMENT_USE_EXTERNAL_GLES3 AND NOT FILAMEN
|
||||
src/opengl/gl_headers.h
|
||||
src/opengl/GLUtils.cpp
|
||||
src/opengl/GLUtils.h
|
||||
src/opengl/OpenGLBlitter.cpp
|
||||
src/opengl/OpenGLBlitter.h
|
||||
src/opengl/OpenGLContext.cpp
|
||||
src/opengl/OpenGLContext.h
|
||||
src/opengl/OpenGLDriver.cpp
|
||||
@@ -89,7 +87,6 @@ if (FILAMENT_SUPPORTS_OPENGL AND NOT FILAMENT_USE_EXTERNAL_GLES3 AND NOT FILAMEN
|
||||
endif ()
|
||||
if (ANDROID)
|
||||
list(APPEND SRCS src/opengl/platforms/ExternalStreamManagerAndroid.cpp)
|
||||
list(APPEND SRCS src/android/ExternalTextureManagerAndroid.cpp)
|
||||
list(APPEND SRCS src/opengl/platforms/PlatformEGLAndroid.cpp)
|
||||
elseif (IOS)
|
||||
list(APPEND SRCS src/opengl/platforms/PlatformCocoaTouchGL.mm)
|
||||
|
||||
@@ -788,7 +788,6 @@ enum class BlendFunction : uint8_t {
|
||||
//! Stream for external textures
|
||||
enum class StreamType {
|
||||
NATIVE, //!< Not synchronized but copy-free. Good for video.
|
||||
TEXTURE_ID, //!< Synchronized, but GL-only and incurs copies. Good for AR on devices before API 26.
|
||||
ACQUIRED, //!< Synchronized, copy-free, and take a release callback. Good for AR but requires API 26+.
|
||||
};
|
||||
|
||||
|
||||
@@ -246,11 +246,6 @@ DECL_DRIVER_API_R_N(backend::SwapChainHandle, createSwapChainHeadless,
|
||||
uint32_t, height,
|
||||
uint64_t, flags)
|
||||
|
||||
DECL_DRIVER_API_R_N(backend::StreamHandle, createStreamFromTextureId,
|
||||
intptr_t, externalTextureId,
|
||||
uint32_t, width,
|
||||
uint32_t, height)
|
||||
|
||||
DECL_DRIVER_API_R_0(backend::TimerQueryHandle, createTimerQuery)
|
||||
|
||||
|
||||
@@ -461,14 +456,6 @@ DECL_DRIVER_API_N(readPixels,
|
||||
uint32_t, height,
|
||||
backend::PixelBufferDescriptor&&, data)
|
||||
|
||||
DECL_DRIVER_API_N(readStreamPixels,
|
||||
backend::StreamHandle, sh,
|
||||
uint32_t, x,
|
||||
uint32_t, y,
|
||||
uint32_t, width,
|
||||
uint32_t, height,
|
||||
backend::PixelBufferDescriptor&&, data)
|
||||
|
||||
/*
|
||||
* Rendering operations
|
||||
* --------------------
|
||||
|
||||
@@ -82,15 +82,6 @@ public:
|
||||
virtual void detach(Stream* stream) noexcept = 0;
|
||||
virtual void updateTexImage(Stream* stream, int64_t* timestamp) noexcept = 0;
|
||||
|
||||
// external texture storage
|
||||
virtual ExternalTexture* createExternalTextureStorage() noexcept = 0;
|
||||
|
||||
// this is called synchronously in the application thread (NOT the Driver thread)
|
||||
virtual void reallocateExternalStorage(ExternalTexture* ets,
|
||||
uint32_t w, uint32_t h, TextureFormat format) noexcept = 0;
|
||||
|
||||
virtual void destroyExternalTextureStorage(ExternalTexture* ets) noexcept = 0;
|
||||
|
||||
// The method allows platforms to convert a user-supplied external image object into a new type
|
||||
// (e.g. HardwareBuffer => EGLImage). It makes sense for the default implementation to do nothing.
|
||||
virtual AcquiredImage transformAcquiredImage(AcquiredImage source) noexcept { return source; }
|
||||
|
||||
@@ -1,222 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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 "ExternalTextureManagerAndroid.h"
|
||||
|
||||
#include <utils/api_level.h>
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
using namespace utils;
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
template <typename T>
|
||||
static void loadSymbol(T*& pfn, const char *symbol) noexcept {
|
||||
pfn = (T*)dlsym(RTLD_DEFAULT, symbol);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
namespace ndk {
|
||||
/*
|
||||
* This mimics the GraphicBuffer class for pre-API 26
|
||||
*/
|
||||
template<typename NATIVE_TYPE, typename REF>
|
||||
struct ANativeObjectBase : public NATIVE_TYPE, public REF {
|
||||
};
|
||||
|
||||
struct android_native_base_t {
|
||||
unsigned int magic;
|
||||
unsigned int version;
|
||||
void* reserved[4];
|
||||
void (* incRef)(struct android_native_base_t* base);
|
||||
void (* decRef)(struct android_native_base_t* base);
|
||||
};
|
||||
|
||||
struct ANativeWindowBuffer {
|
||||
struct android_native_base_t common;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
unsigned int stride;
|
||||
unsigned int format;
|
||||
unsigned int usage_deprecated;
|
||||
uintptr_t layerCount;
|
||||
void* reserved[1];
|
||||
const void* handle;
|
||||
uint64_t usage;
|
||||
void* reserved_proc[8 - (sizeof(uint64_t) / sizeof(void*))];
|
||||
};
|
||||
|
||||
struct RefBase {
|
||||
virtual ~RefBase() = default;
|
||||
void* ref;
|
||||
};
|
||||
|
||||
struct GraphicBuffer : public ANativeObjectBase<ANativeWindowBuffer, RefBase> {
|
||||
};
|
||||
struct GraphicBufferWrapper {
|
||||
GraphicBuffer* graphicBuffer;
|
||||
};
|
||||
} // namespace ndk
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
using namespace ndk;
|
||||
|
||||
struct EGLExternalTexture : public ExternalTextureManagerAndroid::ExternalTexture {
|
||||
GraphicBufferWrapper* graphicBufferWrapper = nullptr;
|
||||
};
|
||||
|
||||
ExternalTextureManagerAndroid& ExternalTextureManagerAndroid::create() noexcept {
|
||||
return *(new ExternalTextureManagerAndroid{});
|
||||
}
|
||||
|
||||
void ExternalTextureManagerAndroid::destroy(ExternalTextureManagerAndroid* pExternalTextureManager) noexcept {
|
||||
delete pExternalTextureManager;
|
||||
}
|
||||
|
||||
// called on gl thread
|
||||
ExternalTextureManagerAndroid::ExternalTextureManagerAndroid() noexcept
|
||||
: mVm(VirtualMachineEnv::get()) {
|
||||
}
|
||||
|
||||
// not quite sure on which thread this is going to be called
|
||||
ExternalTextureManagerAndroid::~ExternalTextureManagerAndroid() noexcept {
|
||||
if (__builtin_available(android 26, *)) {
|
||||
} else {
|
||||
if (mGraphicBufferClass) {
|
||||
JNIEnv* env = VirtualMachineEnv::getThreadEnvironment();
|
||||
if (env) {
|
||||
env->DeleteGlobalRef(mGraphicBufferClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// called on gl thread
|
||||
Platform::ExternalTexture* ExternalTextureManagerAndroid::createExternalTexture() noexcept {
|
||||
if (__builtin_available(android 26, *)) {
|
||||
} else {
|
||||
// initialize java stuff on-demand
|
||||
if (!mGraphicBufferClass) {
|
||||
JNIEnv* env = mVm.getEnvironment();
|
||||
mGraphicBufferClass = env->FindClass("android/view/GraphicBuffer");
|
||||
mGraphicBuffer_nCreateGraphicBuffer = env->GetStaticMethodID(
|
||||
mGraphicBufferClass, "nCreateGraphicBuffer", "(IIII)J");
|
||||
mGraphicBuffer_nDestroyGraphicBuffer = env->GetStaticMethodID(
|
||||
mGraphicBufferClass, "nDestroyGraphicBuffer", "(J)V");
|
||||
|
||||
mGraphicBufferClass = static_cast<jclass>(env->NewGlobalRef(mGraphicBufferClass));
|
||||
}
|
||||
}
|
||||
EGLExternalTexture* ets = new EGLExternalTexture;
|
||||
return ets;
|
||||
}
|
||||
|
||||
// called on app thread
|
||||
void ExternalTextureManagerAndroid::reallocate(
|
||||
Platform::ExternalTexture* ets, uint32_t w, uint32_t h,
|
||||
TextureFormat format, uint64_t usage) noexcept {
|
||||
destroyStorage(ets);
|
||||
alloc(ets, w, h, format, usage);
|
||||
}
|
||||
|
||||
// called on gl thread
|
||||
void ExternalTextureManagerAndroid::destroy(Platform::ExternalTexture* ets) noexcept {
|
||||
destroyStorage(ets);
|
||||
delete static_cast<EGLExternalTexture*>(ets);
|
||||
}
|
||||
|
||||
// called on app thread
|
||||
void ExternalTextureManagerAndroid::alloc(
|
||||
Platform::ExternalTexture* t,
|
||||
uint32_t w, uint32_t h, TextureFormat format, uint64_t usage) noexcept {
|
||||
|
||||
EGLExternalTexture* ets = static_cast<EGLExternalTexture*>(t);
|
||||
|
||||
AHardwareBuffer_Desc desc = { w, h, 1, 0, usage, 0, 0, 0 };
|
||||
switch (format) {
|
||||
case TextureFormat::RGB8:
|
||||
// don't use R8G8B8 here because some drivers produce garbled images
|
||||
desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM;
|
||||
break;
|
||||
case TextureFormat::RGBA8:
|
||||
desc.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
|
||||
break;
|
||||
case TextureFormat::RGB565:
|
||||
desc.format = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
|
||||
break;
|
||||
case TextureFormat::RGB10_A2:
|
||||
desc.format = AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM;
|
||||
break;
|
||||
default:
|
||||
slog.e << "Unsupported format " << (int)format << ", use RGBA8 or RGB8 only."
|
||||
<< io::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (__builtin_available(android 26, *)) {
|
||||
// allocate new storage...
|
||||
AHardwareBuffer* buffer = nullptr;
|
||||
if (AHardwareBuffer_allocate(&desc, &buffer) < 0) {
|
||||
slog.e << "AHardwareBuffer_allocate() failed" << io::endl;
|
||||
return;
|
||||
}
|
||||
ets->hardwareBuffer = buffer;
|
||||
} else {
|
||||
// note: This is called on the application thread (not the GL thread)
|
||||
JNIEnv* env = VirtualMachineEnv::getThreadEnvironment();
|
||||
if (!env) {
|
||||
return; // this should not happen
|
||||
}
|
||||
|
||||
jlong graphicBufferWrapperJni = env->CallStaticLongMethod(mGraphicBufferClass,
|
||||
mGraphicBuffer_nCreateGraphicBuffer, w, h, desc.format, usage);
|
||||
VirtualMachineEnv::handleException(env);
|
||||
|
||||
if (graphicBufferWrapperJni) {
|
||||
GraphicBuffer* const gb = ((GraphicBufferWrapper*)graphicBufferWrapperJni)->graphicBuffer;
|
||||
ets->graphicBufferWrapper = (GraphicBufferWrapper*)graphicBufferWrapperJni;
|
||||
ets->clientBuffer = static_cast<ANativeWindowBuffer*>(gb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// called on gl thread
|
||||
void ExternalTextureManagerAndroid::destroyStorage(Platform::ExternalTexture* t) noexcept {
|
||||
EGLExternalTexture* ets = static_cast<EGLExternalTexture*>(t);
|
||||
if (__builtin_available(android 26, *)) {
|
||||
// destroy the current storage if any
|
||||
if (ets->hardwareBuffer) {
|
||||
AHardwareBuffer_release(ets->hardwareBuffer);
|
||||
ets->hardwareBuffer = nullptr;
|
||||
}
|
||||
} else {
|
||||
if (ets->graphicBufferWrapper) {
|
||||
JNIEnv* env = VirtualMachineEnv::get().getEnvironment();
|
||||
env->CallStaticVoidMethod(mGraphicBufferClass,
|
||||
mGraphicBuffer_nDestroyGraphicBuffer, (jlong)ets->graphicBufferWrapper);
|
||||
VirtualMachineEnv::handleException(env);
|
||||
ets->graphicBufferWrapper = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef TNT_FILAMENT_DRIVER_ANDROID_EXTERNAL_TEXTURE_MANAGER_ANDROID_H
|
||||
#define TNT_FILAMENT_DRIVER_ANDROID_EXTERNAL_TEXTURE_MANAGER_ANDROID_H
|
||||
|
||||
#include "private/backend/VirtualMachineEnv.h"
|
||||
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/Platform.h>
|
||||
|
||||
#include <android/api-level.h>
|
||||
#include <android/hardware_buffer.h>
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
/*
|
||||
* ExternalTextureManagerAndroid::ExternalTexture is basically a wrapper for AHardwareBuffer.
|
||||
*
|
||||
* This class doesn't rely on GL or EGL, and could be used for other Android platform if needed
|
||||
* (e.g. Vulkan).
|
||||
*
|
||||
* ExternalTextureManagerAndroid handle allocation/destruction using either Java or the NDK,
|
||||
* whichever is available.
|
||||
*/
|
||||
class ExternalTextureManagerAndroid {
|
||||
public:
|
||||
|
||||
struct ExternalTexture : public Platform::ExternalTexture {
|
||||
void* clientBuffer = nullptr;
|
||||
AHardwareBuffer* hardwareBuffer = nullptr;
|
||||
};
|
||||
|
||||
// must be called on backend thread
|
||||
static ExternalTextureManagerAndroid& create() noexcept;
|
||||
|
||||
// must be called on backend thread
|
||||
static void destroy(ExternalTextureManagerAndroid* pExternalTextureManager) noexcept;
|
||||
|
||||
// must be called on backend thread (only because we don't synchronize
|
||||
Platform::ExternalTexture* createExternalTexture() noexcept;
|
||||
|
||||
// called on app thread
|
||||
void reallocate(
|
||||
Platform::ExternalTexture* ets, uint32_t w, uint32_t h,
|
||||
TextureFormat format, uint64_t usage) noexcept;
|
||||
|
||||
// must be called on backend thread
|
||||
void destroy(Platform::ExternalTexture* ets) noexcept;
|
||||
|
||||
private:
|
||||
ExternalTextureManagerAndroid() noexcept;
|
||||
~ExternalTextureManagerAndroid() noexcept;
|
||||
|
||||
// called on app thread
|
||||
void alloc(Platform::ExternalTexture* ets,
|
||||
uint32_t w, uint32_t h, TextureFormat format, uint64_t usage) noexcept;
|
||||
|
||||
// called on gl thread
|
||||
void destroyStorage(Platform::ExternalTexture* ets) noexcept;
|
||||
|
||||
VirtualMachineEnv& mVm;
|
||||
|
||||
jclass mGraphicBufferClass = nullptr;
|
||||
jmethodID mGraphicBuffer_nCreateGraphicBuffer = nullptr;
|
||||
jmethodID mGraphicBuffer_nDestroyGraphicBuffer = nullptr;
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
#endif // TNT_FILAMENT_DRIVER_ANDROID_EXTERNAL_TEXTURE_MANAGER_ANDROID_H
|
||||
@@ -359,10 +359,6 @@ void MetalDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch,
|
||||
construct_handle<MetalSwapChain>(sch, *mContext, width, height, flags);
|
||||
}
|
||||
|
||||
void MetalDriver::createStreamFromTextureIdR(Handle<HwStream>, intptr_t externalTextureId,
|
||||
uint32_t width, uint32_t height) {
|
||||
}
|
||||
|
||||
void MetalDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {
|
||||
// nothing to do, timer query was constructed in createTimerQueryS
|
||||
}
|
||||
@@ -431,10 +427,6 @@ Handle<HwSwapChain> MetalDriver::createSwapChainHeadlessS() noexcept {
|
||||
return alloc_handle<MetalSwapChain>();
|
||||
}
|
||||
|
||||
Handle<HwStream> MetalDriver::createStreamFromTextureIdS() noexcept {
|
||||
return {};
|
||||
}
|
||||
|
||||
Handle<HwTimerQuery> MetalDriver::createTimerQueryS() noexcept {
|
||||
// The handle must be constructed here, as a synchronous call to getTimerQueryValue might happen
|
||||
// before createTimerQueryR is executed.
|
||||
@@ -1053,11 +1045,6 @@ void MetalDriver::readPixels(Handle<HwRenderTarget> src, uint32_t x, uint32_t y,
|
||||
}];
|
||||
}
|
||||
|
||||
void MetalDriver::readStreamPixels(Handle<HwStream> sh, uint32_t x, uint32_t y, uint32_t width,
|
||||
uint32_t height, PixelBufferDescriptor&& data) {
|
||||
|
||||
}
|
||||
|
||||
void MetalDriver::blit(TargetBufferFlags buffers,
|
||||
Handle<HwRenderTarget> dst, Viewport dstRect,
|
||||
Handle<HwRenderTarget> src, Viewport srcRect,
|
||||
|
||||
@@ -308,11 +308,6 @@ void NoopDriver::readPixels(Handle<HwRenderTarget> src,
|
||||
scheduleDestroy(std::move(p));
|
||||
}
|
||||
|
||||
void NoopDriver::readStreamPixels(Handle<HwStream> sh, uint32_t x, uint32_t y, uint32_t width,
|
||||
uint32_t height, PixelBufferDescriptor&& p) {
|
||||
scheduleDestroy(std::move(p));
|
||||
}
|
||||
|
||||
void NoopDriver::blit(TargetBufferFlags buffers,
|
||||
Handle<HwRenderTarget> dst, Viewport dstRect,
|
||||
Handle<HwRenderTarget> src, Viewport srcRect,
|
||||
|
||||
@@ -1,215 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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 "OpenGLBlitter.h"
|
||||
|
||||
#include "GLUtils.h"
|
||||
#include "OpenGLContext.h"
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <math/vec2.h>
|
||||
|
||||
using namespace filament::math;
|
||||
using namespace utils;
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
static const char s_vertexES[] = R"SHADER(#version 300 es
|
||||
in vec4 pos;
|
||||
void main() {
|
||||
gl_Position = pos;
|
||||
}
|
||||
)SHADER";
|
||||
|
||||
static const char s_vertexGL[] = R"SHADER(#version 410 core
|
||||
in vec4 pos;
|
||||
void main() {
|
||||
gl_Position = pos;
|
||||
}
|
||||
)SHADER";
|
||||
|
||||
static const char s_fragmentES[] = R"SHADER(#version 300 es
|
||||
#extension GL_OES_EGL_image_external_essl3 : enable
|
||||
precision mediump float;
|
||||
uniform samplerExternalOES sampler;
|
||||
out vec4 fragColor;
|
||||
void main() {
|
||||
fragColor = texelFetch(sampler, ivec2(gl_FragCoord.xy), 0);
|
||||
}
|
||||
)SHADER";
|
||||
|
||||
static const char s_fragmentGL[] = R"SHADER(#version 410 core
|
||||
precision mediump float;
|
||||
uniform sampler2D sampler;
|
||||
out vec4 fragColor;
|
||||
void main() {
|
||||
fragColor = texelFetch(sampler, ivec2(gl_FragCoord.xy), 0);
|
||||
}
|
||||
)SHADER";
|
||||
|
||||
void OpenGLBlitter::init() noexcept {
|
||||
glGenSamplers(1, &mSampler);
|
||||
glSamplerParameteri(mSampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glSamplerParameteri(mSampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glSamplerParameteri(mSampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(mSampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glSamplerParameteri(mSampler, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
|
||||
GLint status;
|
||||
char const* vsource[2] = { s_vertexES, s_vertexGL };
|
||||
char const* fsource[2] = { s_fragmentES, s_fragmentGL };
|
||||
const size_t index = BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GLES ? 0 : 1;
|
||||
|
||||
mVertexShader = glCreateShader(GL_VERTEX_SHADER);
|
||||
glShaderSource(mVertexShader, 1, vsource + index, nullptr);
|
||||
glCompileShader(mVertexShader);
|
||||
glGetShaderiv(mVertexShader, GL_COMPILE_STATUS, &status);
|
||||
assert_invariant(status == GL_TRUE);
|
||||
|
||||
mFragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
|
||||
glShaderSource(mFragmentShader, 1, fsource + index, nullptr);
|
||||
glCompileShader(mFragmentShader);
|
||||
glGetShaderiv(mFragmentShader, GL_COMPILE_STATUS, &status);
|
||||
assert_invariant(status == GL_TRUE);
|
||||
|
||||
mProgram = glCreateProgram();
|
||||
glAttachShader(mProgram, mVertexShader);
|
||||
glAttachShader(mProgram, mFragmentShader);
|
||||
glLinkProgram(mProgram);
|
||||
glGetProgramiv(mProgram, GL_LINK_STATUS, &status);
|
||||
assert_invariant(status == GL_TRUE);
|
||||
|
||||
glUseProgram(mProgram);
|
||||
GLint loc = glGetUniformLocation(mProgram, "sampler");
|
||||
GLuint tmu = 0;
|
||||
glUniform1i(loc, tmu);
|
||||
|
||||
glGenFramebuffers(1, &mFBO);
|
||||
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
}
|
||||
|
||||
void OpenGLBlitter::terminate() noexcept {
|
||||
glDeleteSamplers(1, &mSampler);
|
||||
glDetachShader(mProgram, mVertexShader);
|
||||
glDetachShader(mProgram, mFragmentShader);
|
||||
glDeleteShader(mVertexShader);
|
||||
glDeleteShader(mFragmentShader);
|
||||
glDeleteProgram(mProgram);
|
||||
glDeleteFramebuffers(1, &mFBO);
|
||||
}
|
||||
|
||||
void OpenGLBlitter::blit(GLuint srcTextureExternal, GLuint dstTexture2d, GLuint w, GLuint h) noexcept {
|
||||
const float2 vtx[3] = {{ -1.0f, 3.0f },
|
||||
{ -1.0f, -1.0f },
|
||||
{ 3.0f, -1.0f }};
|
||||
|
||||
// we're using tmu 0 as the source texture
|
||||
GLuint tmu = 0;
|
||||
|
||||
// source texture
|
||||
glBindSampler(tmu, mSampler);
|
||||
glBindTexture(GL_TEXTURE_EXTERNAL_OES, srcTextureExternal);
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
|
||||
// destination texture
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dstTexture2d, 0);
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
CHECK_GL_FRAMEBUFFER_STATUS(utils::slog.e, GL_FRAMEBUFFER)
|
||||
|
||||
// geometry
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vtx);
|
||||
|
||||
// blit...
|
||||
glViewport(0, 0, w, h);
|
||||
glUseProgram(mProgram);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
}
|
||||
|
||||
void OpenGLBlitter::State::save() noexcept {
|
||||
mHasState = true;
|
||||
// TODO: technically we should also save glVertexAttribPointer
|
||||
GLuint tmu = 0;
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &framebuffer);
|
||||
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &array);
|
||||
glGetIntegerv(GL_CURRENT_PROGRAM, &program);
|
||||
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||
glGetIntegerv(GL_COLOR_WRITEMASK, writeMask);
|
||||
scissorTest = glIsEnabled(GL_SCISSOR_TEST);
|
||||
stencilTest = glIsEnabled(GL_STENCIL_TEST);
|
||||
cullFace = glIsEnabled(GL_CULL_FACE);
|
||||
glGetVertexAttribiv(0, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &vertexAttrib);
|
||||
|
||||
// save the current active texture first
|
||||
glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTexture);
|
||||
|
||||
// we're using tmu 0 as the source texture
|
||||
glActiveTexture(GL_TEXTURE0 + tmu);
|
||||
|
||||
// save what depends on glActiveTexture
|
||||
glGetIntegerv(GL_SAMPLER_BINDING, &sampler);
|
||||
glGetIntegerv(GL_TEXTURE_BINDING_2D, &texture);
|
||||
|
||||
/*
|
||||
* Set the state
|
||||
*/
|
||||
|
||||
// we're using tmu 0 as the source texture
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
}
|
||||
|
||||
void OpenGLBlitter::State::restore() noexcept {
|
||||
GLuint tmu = 0;
|
||||
glColorMask(
|
||||
(GLboolean)writeMask[0],
|
||||
(GLboolean)writeMask[1],
|
||||
(GLboolean)writeMask[2],
|
||||
(GLboolean)writeMask[3]);
|
||||
if (cullFace) {
|
||||
glEnable(GL_CULL_FACE);
|
||||
}
|
||||
if (stencilTest) {
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
}
|
||||
if (scissorTest) {
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
}
|
||||
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
|
||||
glUseProgram(static_cast<GLuint>(program));
|
||||
glBindBuffer(GL_ARRAY_BUFFER, static_cast<GLuint>(array));
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, static_cast<GLuint>(framebuffer));
|
||||
if (!vertexAttrib) {
|
||||
glDisableVertexAttribArray(0);
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, static_cast<GLuint>(texture));
|
||||
glBindSampler(tmu, static_cast<GLuint>(sampler));
|
||||
glActiveTexture(static_cast<GLenum>(activeTexture));
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
}
|
||||
|
||||
} // namespace filament::backend
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef TNT_FILAMENT_BACKEND_OPENGL_OPENGLBLITTER_H
|
||||
#define TNT_FILAMENT_BACKEND_OPENGL_OPENGLBLITTER_H
|
||||
|
||||
#include <utils/compiler.h>
|
||||
#include "gl_headers.h"
|
||||
|
||||
namespace filament::backend {
|
||||
|
||||
class OpenGLContext;
|
||||
|
||||
class OpenGLBlitter {
|
||||
public:
|
||||
explicit OpenGLBlitter(OpenGLContext& context) noexcept : mContext(context) {}
|
||||
|
||||
void init() noexcept;
|
||||
void terminate() noexcept;
|
||||
|
||||
void blit(GLuint srcTextureExternal, GLuint dstTexture2d, GLuint w, GLuint h) noexcept;
|
||||
|
||||
class State {
|
||||
bool mHasState = false;
|
||||
GLint activeTexture, sampler, texture, framebuffer, array, vertexAttrib, program;
|
||||
GLboolean stencilTest, scissorTest, cullFace;
|
||||
GLint viewport[4], writeMask[4];
|
||||
void save() noexcept;
|
||||
void restore() noexcept;
|
||||
public:
|
||||
void setup() noexcept {
|
||||
if (UTILS_UNLIKELY(!mHasState)) {
|
||||
save();
|
||||
}
|
||||
}
|
||||
~State() noexcept {
|
||||
if (UTILS_UNLIKELY(mHasState)) {
|
||||
restore();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
UTILS_UNUSED OpenGLContext& mContext;
|
||||
GLuint mSampler{};
|
||||
GLuint mVertexShader{};
|
||||
GLuint mFragmentShader{};
|
||||
GLuint mProgram{};
|
||||
GLuint mFBO{};
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
#endif // TNT_FILAMENT_BACKEND_OPENGL_OPENGLBLITTER_H
|
||||
@@ -20,7 +20,6 @@
|
||||
#include "private/backend/OpenGLPlatform.h"
|
||||
|
||||
#include "CommandStreamDispatcher.h"
|
||||
#include "OpenGLBlitter.h"
|
||||
#include "OpenGLDriverFactory.h"
|
||||
#include "OpenGLProgram.h"
|
||||
#include "OpenGLTimerQuery.h"
|
||||
@@ -168,13 +167,6 @@ OpenGLDriver::OpenGLDriver(OpenGLPlatform* platform) noexcept
|
||||
slog.i << "OS version: " << mPlatform.getOSVersion() << io::endl;
|
||||
#endif
|
||||
|
||||
// Initialize the blitter only if we have OES_EGL_image_external_essl3
|
||||
if (mContext.ext.OES_EGL_image_external_essl3) {
|
||||
mOpenGLBlitter = new OpenGLBlitter(mContext);
|
||||
mOpenGLBlitter->init();
|
||||
mContext.resetProgram();
|
||||
}
|
||||
|
||||
if (mContext.ext.EXT_disjoint_timer_query ||
|
||||
BACKEND_OPENGL_VERSION == BACKEND_OPENGL_VERSION_GL) {
|
||||
// timer queries are available
|
||||
@@ -197,7 +189,6 @@ OpenGLDriver::OpenGLDriver(OpenGLPlatform* platform) noexcept
|
||||
}
|
||||
|
||||
OpenGLDriver::~OpenGLDriver() noexcept {
|
||||
delete mOpenGLBlitter;
|
||||
}
|
||||
|
||||
Dispatcher OpenGLDriver::getDispatcher() const noexcept {
|
||||
@@ -223,9 +214,6 @@ void OpenGLDriver::terminate() {
|
||||
glDeleteSamplers(1, &item.second);
|
||||
}
|
||||
mSamplerMap.clear();
|
||||
if (mOpenGLBlitter) {
|
||||
mOpenGLBlitter->terminate();
|
||||
}
|
||||
|
||||
delete mTimerQueryImpl;
|
||||
|
||||
@@ -381,10 +369,6 @@ Handle<HwSwapChain> OpenGLDriver::createSwapChainHeadlessS() noexcept {
|
||||
return initHandle<HwSwapChain>();
|
||||
}
|
||||
|
||||
Handle<HwStream> OpenGLDriver::createStreamFromTextureIdS() noexcept {
|
||||
return initHandle<GLStream>();
|
||||
}
|
||||
|
||||
Handle<HwTimerQuery> OpenGLDriver::createTimerQueryS() noexcept {
|
||||
return initHandle<GLTimerQuery>();
|
||||
}
|
||||
@@ -1137,24 +1121,6 @@ void OpenGLDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch,
|
||||
sc->swapChain = mPlatform.createSwapChain(width, height, flags);
|
||||
}
|
||||
|
||||
void OpenGLDriver::createStreamFromTextureIdR(Handle<HwStream> sh,
|
||||
intptr_t externalTextureId, uint32_t width, uint32_t height) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
GLStream* s = handle_cast<GLStream*>(sh);
|
||||
// It would be better if we could query the externalTextureId size, unfortunately
|
||||
// this is not supported in GL for GL_TEXTURE_EXTERNAL_OES targets
|
||||
s->width = width;
|
||||
s->height = height;
|
||||
s->gl.externalTextureId = static_cast<GLuint>(externalTextureId);
|
||||
s->streamType = StreamType::TEXTURE_ID;
|
||||
glGenTextures(GLStream::ROUND_ROBIN_TEXTURE_COUNT, s->user_thread.read);
|
||||
glGenTextures(GLStream::ROUND_ROBIN_TEXTURE_COUNT, s->user_thread.write);
|
||||
for (auto& info : s->user_thread.infos) {
|
||||
info.ets = mPlatform.createExternalTextureStorage();
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {
|
||||
DEBUG_MARKER()
|
||||
|
||||
@@ -1301,15 +1267,6 @@ void OpenGLDriver::destroyStream(Handle<HwStream> sh) {
|
||||
}
|
||||
if (s->streamType == StreamType::NATIVE) {
|
||||
mPlatform.destroyStream(s->stream);
|
||||
} else if (s->streamType == StreamType::TEXTURE_ID) {
|
||||
glDeleteTextures(GLStream::ROUND_ROBIN_TEXTURE_COUNT, s->user_thread.read);
|
||||
glDeleteTextures(GLStream::ROUND_ROBIN_TEXTURE_COUNT, s->user_thread.write);
|
||||
if (s->gl.fbo) {
|
||||
glDeleteFramebuffers(1, &s->gl.fbo);
|
||||
}
|
||||
for (auto const& info : s->user_thread.infos) {
|
||||
mPlatform.destroyExternalTextureStorage(info.ets);
|
||||
}
|
||||
}
|
||||
destruct(sh, s);
|
||||
}
|
||||
@@ -1368,7 +1325,6 @@ void OpenGLDriver::setAcquiredImage(Handle<HwStream> sh, void* hwbuffer,
|
||||
|
||||
void OpenGLDriver::updateStreams(DriverApi* driver) {
|
||||
if (UTILS_UNLIKELY(!mExternalStreams.empty())) {
|
||||
OpenGLBlitter::State state;
|
||||
for (GLTexture* t : mExternalStreams) {
|
||||
assert_invariant(t);
|
||||
|
||||
@@ -1379,11 +1335,6 @@ void OpenGLDriver::updateStreams(DriverApi* driver) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (s->streamType == StreamType::TEXTURE_ID) {
|
||||
state.setup();
|
||||
updateStreamTexId(t, driver);
|
||||
}
|
||||
|
||||
if (s->streamType == StreamType::ACQUIRED) {
|
||||
updateStreamAcquired(t, driver);
|
||||
}
|
||||
@@ -2080,20 +2031,12 @@ void OpenGLDriver::setExternalStream(Handle<HwTexture> th, Handle<HwStream> sh)
|
||||
|
||||
UTILS_NOINLINE
|
||||
void OpenGLDriver::attachStream(GLTexture* t, GLStream* hwStream) noexcept {
|
||||
auto& gl = mContext;
|
||||
mExternalStreams.push_back(t);
|
||||
|
||||
switch (hwStream->streamType) {
|
||||
case StreamType::NATIVE:
|
||||
mPlatform.attach(hwStream->stream, t->gl.id);
|
||||
break;
|
||||
case StreamType::TEXTURE_ID:
|
||||
assert_invariant(t->target == SamplerType::SAMPLER_EXTERNAL);
|
||||
// The texture doesn't need a texture name anymore, get rid of it
|
||||
gl.unbindTexture(t->gl.target, t->gl.id);
|
||||
glDeleteTextures(1, &t->gl.id);
|
||||
t->gl.id = hwStream->user_thread.read[hwStream->user_thread.cur];
|
||||
break;
|
||||
case StreamType::ACQUIRED:
|
||||
break;
|
||||
}
|
||||
@@ -2115,8 +2058,6 @@ void OpenGLDriver::detachStream(GLTexture* t) noexcept {
|
||||
mPlatform.detach(t->hwStream->stream);
|
||||
// ^ this deletes the texture id
|
||||
break;
|
||||
case StreamType::TEXTURE_ID:
|
||||
break;
|
||||
case StreamType::ACQUIRED:
|
||||
gl.unbindTexture(t->gl.target, t->gl.id);
|
||||
glDeleteTextures(1, &t->gl.id);
|
||||
@@ -2141,7 +2082,6 @@ void OpenGLDriver::replaceStream(GLTexture* texture, GLStream* newStream) noexce
|
||||
mPlatform.detach(texture->hwStream->stream);
|
||||
// ^ this deletes the texture id
|
||||
break;
|
||||
case StreamType::TEXTURE_ID:
|
||||
case StreamType::ACQUIRED:
|
||||
break;
|
||||
}
|
||||
@@ -2151,10 +2091,6 @@ void OpenGLDriver::replaceStream(GLTexture* texture, GLStream* newStream) noexce
|
||||
glGenTextures(1, &texture->gl.id);
|
||||
mPlatform.attach(newStream->stream, texture->gl.id);
|
||||
break;
|
||||
case StreamType::TEXTURE_ID:
|
||||
assert_invariant(texture->target == SamplerType::SAMPLER_EXTERNAL);
|
||||
texture->gl.id = newStream->user_thread.read[newStream->user_thread.cur];
|
||||
break;
|
||||
case StreamType::ACQUIRED:
|
||||
// Just re-use the old texture id.
|
||||
break;
|
||||
@@ -2524,179 +2460,6 @@ void OpenGLDriver::updateStreamAcquired(GLTexture* gltexture, DriverApi* driver)
|
||||
});
|
||||
}
|
||||
|
||||
#define DEBUG_NO_EXTERNAL_STREAM_COPY false
|
||||
|
||||
void OpenGLDriver::updateStreamTexId(GLTexture* t, DriverApi* driver) noexcept {
|
||||
SYSTRACE_CALL();
|
||||
auto& gl = mContext;
|
||||
|
||||
GLStream* s = static_cast<GLStream*>(t->hwStream);
|
||||
assert_invariant(s);
|
||||
assert_invariant(s->streamType == StreamType::TEXTURE_ID);
|
||||
|
||||
// round-robin to the next texture name
|
||||
if (UTILS_UNLIKELY(DEBUG_NO_EXTERNAL_STREAM_COPY ||
|
||||
gl.bugs.disable_shared_context_draws || !mOpenGLBlitter)) {
|
||||
driver->queueCommand([this, t, s]() {
|
||||
// the stream may have been destroyed since we enqueued the command
|
||||
// also make sure that this texture is still associated with the same stream
|
||||
auto& streams = mExternalStreams;
|
||||
if (UTILS_LIKELY(std::find(streams.begin(), streams.end(), t) != streams.end()) &&
|
||||
(t->hwStream == s)) {
|
||||
t->gl.id = s->gl.externalTextureId;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
s->user_thread.cur = uint8_t(
|
||||
(s->user_thread.cur + 1) % GLStream::ROUND_ROBIN_TEXTURE_COUNT);
|
||||
GLuint writeTexture = s->user_thread.write[s->user_thread.cur];
|
||||
GLuint readTexture = s->user_thread.read[s->user_thread.cur];
|
||||
|
||||
// Make sure we're using the proper size
|
||||
GLStream::Info& info = s->user_thread.infos[s->user_thread.cur];
|
||||
if (UTILS_UNLIKELY(info.width != s->width || info.height != s->height)) {
|
||||
|
||||
// nothing guarantees that this buffer is free (i.e. has been consumed by the
|
||||
// GL thread), so we could potentially cause a glitch by reallocating the
|
||||
// texture here. This should be very rare though.
|
||||
// This could be fixed by always using a new temporary texture here, and
|
||||
// replacing it in the queueCommand() below. imho, not worth it.
|
||||
|
||||
info.width = s->width;
|
||||
info.height = s->height;
|
||||
|
||||
Platform::ExternalTexture* ets = s->user_thread.infos[s->user_thread.cur].ets;
|
||||
mPlatform.reallocateExternalStorage(ets, info.width, info.height, TextureFormat::RGB8);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, writeTexture);
|
||||
glBindTexture(GL_TEXTURE_EXTERNAL_OES, readTexture);
|
||||
#ifdef GL_OES_EGL_image
|
||||
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)ets->image);
|
||||
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)ets->image);
|
||||
#endif
|
||||
}
|
||||
|
||||
// copy the texture...
|
||||
#ifndef NDEBUG
|
||||
if (t->gl.fence) {
|
||||
// we're about to overwrite a buffer that hasn't been consumed
|
||||
slog.d << "OpenGLDriver::updateStream(): about to overwrite buffer " <<
|
||||
int(s->user_thread.cur) << " of Texture at " << t << " of Stream at " << s
|
||||
<< io::endl;
|
||||
}
|
||||
#endif
|
||||
mOpenGLBlitter->blit(s->gl.externalTextureId, writeTexture, s->width, s->height);
|
||||
|
||||
// We need a fence to guarantee that this copy has happened when we need the texture
|
||||
// in OpenGLProgram::updateSamplers(), i.e. when we bind textures just before use.
|
||||
GLsync fence = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
// Per https://www.khronos.org/opengl/wiki/Sync_Object, flush to make sure that the
|
||||
// sync object is in the driver's command queue.
|
||||
glFlush();
|
||||
|
||||
// Update the stream timestamp. It's not clear to me that this is correct; which
|
||||
// timestamp do we really want? Here we use "now" because we have nothing else we
|
||||
// can use.
|
||||
s->user_thread.timestamp = std::chrono::steady_clock::now().time_since_epoch().count();
|
||||
|
||||
driver->queueCommand([this, t, s, fence, readTexture, writeTexture]() {
|
||||
// the stream may have been destroyed since we enqueued the command
|
||||
// also make sure that this texture is still associated with the same stream
|
||||
auto& streams = mExternalStreams;
|
||||
if (UTILS_LIKELY(std::find(streams.begin(), streams.end(), t) != streams.end()) &&
|
||||
(t->hwStream == s)) {
|
||||
if (UTILS_UNLIKELY(t->gl.fence)) {
|
||||
// if the texture still has a fence set, destroy it now, so it's not leaked.
|
||||
glDeleteSync(t->gl.fence);
|
||||
}
|
||||
t->gl.id = readTexture;
|
||||
t->gl.fence = fence;
|
||||
s->gl.externalTexture2DId = writeTexture;
|
||||
} else {
|
||||
glDeleteSync(fence);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLDriver::readStreamPixels(Handle<HwStream> sh,
|
||||
uint32_t x, uint32_t y, uint32_t width, uint32_t height,
|
||||
PixelBufferDescriptor&& p) {
|
||||
DEBUG_MARKER()
|
||||
auto& gl = mContext;
|
||||
|
||||
GLStream* s = handle_cast<GLStream*>(sh);
|
||||
|
||||
if (UTILS_UNLIKELY(s->streamType == StreamType::ACQUIRED)) {
|
||||
PANIC_LOG("readStreamPixels with ACQUIRED streams is not yet implemented.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (UTILS_LIKELY(s->streamType == StreamType::TEXTURE_ID)) {
|
||||
GLuint tid = s->gl.externalTexture2DId;
|
||||
if (tid == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
GLenum glFormat = getFormat(p.format);
|
||||
GLenum glType = getType(p.type);
|
||||
|
||||
gl.pixelStore(GL_PACK_ROW_LENGTH, p.stride);
|
||||
gl.pixelStore(GL_PACK_ALIGNMENT, p.alignment);
|
||||
gl.pixelStore(GL_PACK_SKIP_PIXELS, p.left);
|
||||
gl.pixelStore(GL_PACK_SKIP_ROWS, p.top);
|
||||
|
||||
if (s->gl.fbo == 0) {
|
||||
glGenFramebuffers(1, &s->gl.fbo);
|
||||
}
|
||||
gl.bindFramebuffer(GL_FRAMEBUFFER, s->gl.fbo);
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tid, 0);
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
|
||||
/*
|
||||
* It looks like glReadPixels() behaves differently, or even wrongly,
|
||||
* when the FBO is backed by an EXTERNAL texture...
|
||||
*
|
||||
*
|
||||
* External texture FBO User buffer
|
||||
*
|
||||
* O---+----------------+
|
||||
* | | | .stride .alignment
|
||||
* | | | ----------------------->-->
|
||||
* | | y | O----------------------+--+ low adresses
|
||||
* | | | | | | |
|
||||
* | | w | | | .bottom | |
|
||||
* | V <---------> | | V | |
|
||||
* | +---------+ | | +---------+ | |
|
||||
* | | ^ | | ======> | | | | |
|
||||
* | x | h| | | |.left| | | |
|
||||
* +------>| v | | +---->| | | |
|
||||
* | +.........+ | | +.........+ | |
|
||||
* | | | | |
|
||||
* | | +----------------------+--+ high adresses
|
||||
* +--------------------+
|
||||
*
|
||||
* Origin is at the The image is NOT y-reversed
|
||||
* top-left corner and bottom is counted from
|
||||
* the top! "bottom" is in fact treated
|
||||
* as "top".
|
||||
*/
|
||||
|
||||
// The filament API provides yoffset as the "bottom" offset, therefore it needs to
|
||||
// be corrected to match glReadPixels()'s behavior.
|
||||
y = (s->height - height) - y;
|
||||
|
||||
// TODO: we could use a PBO to make this asynchronous
|
||||
glReadPixels(GLint(x), GLint(y), GLint(width), GLint(height), glFormat, glType, p.buffer);
|
||||
CHECK_GL_ERROR(utils::slog.e)
|
||||
|
||||
gl.bindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
scheduleDestroy(std::move(p));
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Setting rendering state
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -145,7 +145,6 @@ public:
|
||||
};
|
||||
|
||||
struct GLStream : public HwStream {
|
||||
static constexpr size_t ROUND_ROBIN_TEXTURE_COUNT = 3; // 3 maximum
|
||||
using HwStream::HwStream;
|
||||
struct Info {
|
||||
// storage for the read/write textures below
|
||||
@@ -153,29 +152,11 @@ public:
|
||||
GLuint width = 0;
|
||||
GLuint height = 0;
|
||||
};
|
||||
struct {
|
||||
// id of the texture where the external frames are streamed (i.e. the texture
|
||||
// used by SurfaceTexture on Android)
|
||||
GLuint externalTextureId = 0;
|
||||
|
||||
/*
|
||||
* This is for making a cpu copy of the camera frame
|
||||
*/
|
||||
GLuint externalTexture2DId = 0;
|
||||
GLuint fbo = 0;
|
||||
} gl; // 20 bytes
|
||||
|
||||
|
||||
/*
|
||||
* The fields below are accessed from the main application thread
|
||||
* (not the GL thread)
|
||||
*/
|
||||
struct {
|
||||
// texture id used to texture from, always used in the GL thread
|
||||
GLuint read[ROUND_ROBIN_TEXTURE_COUNT]; // 12 bytes
|
||||
// texture id to write into, always used from the user thread
|
||||
GLuint write[ROUND_ROBIN_TEXTURE_COUNT]; // 12 bytes
|
||||
Info infos[ROUND_ROBIN_TEXTURE_COUNT]; // 48 bytes
|
||||
int64_t timestamp = 0;
|
||||
uint8_t cur = 0;
|
||||
AcquiredImage acquired;
|
||||
@@ -375,8 +356,6 @@ private:
|
||||
|
||||
OpenGLPlatform& mPlatform;
|
||||
|
||||
OpenGLBlitter* mOpenGLBlitter = nullptr;
|
||||
void updateStreamTexId(GLTexture* t, DriverApi* driver) noexcept;
|
||||
void updateStreamAcquired(GLTexture* t, DriverApi* driver) noexcept;
|
||||
void updateBuffer(GLBufferObject* buffer, BufferDescriptor const& p,
|
||||
uint32_t byteOffset, uint32_t alignment = 16) noexcept;
|
||||
|
||||
@@ -55,11 +55,6 @@ public:
|
||||
void detach(Stream* stream) noexcept final {}
|
||||
void updateTexImage(Stream* stream, int64_t* timestamp) noexcept final {}
|
||||
|
||||
ExternalTexture* createExternalTextureStorage() noexcept final { return nullptr; }
|
||||
void reallocateExternalStorage(ExternalTexture* ets,
|
||||
uint32_t w, uint32_t h, TextureFormat format) noexcept final { }
|
||||
void destroyExternalTextureStorage(ExternalTexture* ets) noexcept final { }
|
||||
|
||||
int getOSVersion() const noexcept final { return 0; }
|
||||
|
||||
bool pumpEvents() noexcept override;
|
||||
|
||||
@@ -56,11 +56,6 @@ public:
|
||||
void detach(Stream* stream) noexcept final {}
|
||||
void updateTexImage(Stream* stream, int64_t* timestamp) noexcept final {}
|
||||
|
||||
ExternalTexture* createExternalTextureStorage() noexcept final { return nullptr; }
|
||||
void reallocateExternalStorage(ExternalTexture* ets,
|
||||
uint32_t w, uint32_t h, TextureFormat format) noexcept final { }
|
||||
void destroyExternalTextureStorage(ExternalTexture* ets) noexcept final { }
|
||||
|
||||
int getOSVersion() const noexcept final { return 0; }
|
||||
|
||||
bool setExternalImage(void* externalImage, void* texture) noexcept final;
|
||||
|
||||
@@ -51,11 +51,6 @@ public:
|
||||
void detach(Stream* stream) noexcept final override {}
|
||||
void updateTexImage(Stream* stream, int64_t* timestamp) noexcept final override {}
|
||||
|
||||
ExternalTexture* createExternalTextureStorage() noexcept final override { return nullptr; }
|
||||
void reallocateExternalStorage(ExternalTexture* ets,
|
||||
uint32_t w, uint32_t h, TextureFormat format) noexcept final override { }
|
||||
void destroyExternalTextureStorage(ExternalTexture* ets) noexcept final override { }
|
||||
|
||||
int getOSVersion() const noexcept final override { return 0; }
|
||||
};
|
||||
|
||||
|
||||
@@ -62,11 +62,6 @@ public:
|
||||
void detach(Stream* stream) noexcept override {}
|
||||
void updateTexImage(Stream* stream, int64_t* timestamp) noexcept override {}
|
||||
|
||||
ExternalTexture* createExternalTextureStorage() noexcept override { return nullptr; }
|
||||
void reallocateExternalStorage(ExternalTexture* ets,
|
||||
uint32_t w, uint32_t h, TextureFormat format) noexcept override {}
|
||||
void destroyExternalTextureStorage(ExternalTexture* ets) noexcept override {}
|
||||
|
||||
protected:
|
||||
static void logEglError(const char* name) noexcept;
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "opengl/OpenGLDriver.h"
|
||||
#include "opengl/OpenGLContext.h"
|
||||
|
||||
#include "android/ExternalTextureManagerAndroid.h"
|
||||
#include "ExternalStreamManagerAndroid.h"
|
||||
#include "private/backend/VirtualMachineEnv.h"
|
||||
|
||||
@@ -73,8 +72,7 @@ using EGLStream = Platform::Stream;
|
||||
|
||||
PlatformEGLAndroid::PlatformEGLAndroid() noexcept
|
||||
: PlatformEGL(),
|
||||
mExternalStreamManager(ExternalStreamManagerAndroid::create()),
|
||||
mExternalTextureManager(ExternalTextureManagerAndroid::create()) {
|
||||
mExternalStreamManager(ExternalStreamManagerAndroid::create()) {
|
||||
|
||||
char scratch[PROP_VALUE_MAX + 1];
|
||||
int length = __system_property_get("ro.build.version.release", scratch);
|
||||
@@ -104,7 +102,6 @@ PlatformEGLAndroid::~PlatformEGLAndroid() noexcept = default;
|
||||
|
||||
void PlatformEGLAndroid::terminate() noexcept {
|
||||
ExternalStreamManagerAndroid::destroy(&mExternalStreamManager);
|
||||
ExternalTextureManagerAndroid::destroy(&mExternalTextureManager);
|
||||
PlatformEGL::terminate();
|
||||
}
|
||||
|
||||
@@ -167,58 +164,6 @@ void PlatformEGLAndroid::updateTexImage(Stream* stream, int64_t* timestamp) noex
|
||||
mExternalStreamManager.updateTexImage(stream, timestamp);
|
||||
}
|
||||
|
||||
Platform::ExternalTexture* PlatformEGLAndroid::createExternalTextureStorage() noexcept {
|
||||
return mExternalTextureManager.createExternalTexture();
|
||||
}
|
||||
|
||||
void PlatformEGLAndroid::reallocateExternalStorage(
|
||||
Platform::ExternalTexture* externalTexture,
|
||||
uint32_t w, uint32_t h, TextureFormat format) noexcept {
|
||||
if (externalTexture) {
|
||||
if ((EGLImageKHR)externalTexture->image != EGL_NO_IMAGE_KHR) {
|
||||
eglDestroyImageKHR(mEGLDisplay, (EGLImageKHR)externalTexture->image);
|
||||
externalTexture->image = (uintptr_t)EGL_NO_IMAGE_KHR;
|
||||
}
|
||||
|
||||
mExternalTextureManager.reallocate(externalTexture, w, h, format,
|
||||
AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE);
|
||||
|
||||
auto ets = (ExternalTextureManagerAndroid::ExternalTexture*)externalTexture;
|
||||
EGLClientBuffer clientBuffer;
|
||||
if (ets->hardwareBuffer) {
|
||||
clientBuffer = eglGetNativeClientBufferANDROID(ets->hardwareBuffer);
|
||||
if (UTILS_UNLIKELY(!clientBuffer)) {
|
||||
logEglError("eglGetNativeClientBufferANDROID");
|
||||
return;
|
||||
}
|
||||
} else if (ets->clientBuffer) {
|
||||
clientBuffer = (EGLClientBuffer)ets->clientBuffer;
|
||||
} else {
|
||||
// woops, reallocate failed.
|
||||
return;
|
||||
}
|
||||
|
||||
const EGLint attr[] = { EGL_NONE };
|
||||
EGLImageKHR image = eglCreateImageKHR(mEGLDisplay,
|
||||
EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attr);
|
||||
if (UTILS_UNLIKELY(!image)) {
|
||||
logEglError("eglCreateImageKHR");
|
||||
}
|
||||
ets->image = (uintptr_t)image;
|
||||
}
|
||||
}
|
||||
|
||||
void PlatformEGLAndroid::destroyExternalTextureStorage(
|
||||
Platform::ExternalTexture* externalTexture) noexcept {
|
||||
if (externalTexture) {
|
||||
mExternalTextureManager.destroy(externalTexture);
|
||||
if ((EGLImageKHR)externalTexture->image != EGL_NO_IMAGE_KHR) {
|
||||
eglDestroyImageKHR(mEGLDisplay, (EGLImageKHR)externalTexture->image);
|
||||
externalTexture->image = (uintptr_t)EGL_NO_IMAGE_KHR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int PlatformEGLAndroid::getOSVersion() const noexcept {
|
||||
return mOSVersion;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
namespace filament::backend {
|
||||
|
||||
class ExternalStreamManagerAndroid;
|
||||
class ExternalTextureManagerAndroid;
|
||||
|
||||
class PlatformEGLAndroid final : public PlatformEGL {
|
||||
public:
|
||||
@@ -44,17 +43,11 @@ public:
|
||||
void detach(Stream* stream) noexcept final;
|
||||
void updateTexImage(Stream* stream, int64_t* timestamp) noexcept final;
|
||||
|
||||
ExternalTexture* createExternalTextureStorage() noexcept final;
|
||||
void reallocateExternalStorage(ExternalTexture* ets,
|
||||
uint32_t w, uint32_t h, TextureFormat format) noexcept final;
|
||||
void destroyExternalTextureStorage(ExternalTexture* ets) noexcept final;
|
||||
|
||||
AcquiredImage transformAcquiredImage(AcquiredImage source) noexcept final;
|
||||
|
||||
private:
|
||||
int mOSVersion;
|
||||
ExternalStreamManagerAndroid& mExternalStreamManager;
|
||||
ExternalTextureManagerAndroid& mExternalTextureManager;
|
||||
};
|
||||
|
||||
} // namespace filament::backend
|
||||
|
||||
@@ -55,11 +55,6 @@ public:
|
||||
void detach(Stream* stream) noexcept final override {}
|
||||
void updateTexImage(Stream* stream, int64_t* timestamp) noexcept final override {}
|
||||
|
||||
ExternalTexture* createExternalTextureStorage() noexcept final override { return nullptr; }
|
||||
void reallocateExternalStorage(ExternalTexture* ets,
|
||||
uint32_t w, uint32_t h, TextureFormat format) noexcept final override { }
|
||||
void destroyExternalTextureStorage(ExternalTexture* ets) noexcept final override { }
|
||||
|
||||
int getOSVersion() const noexcept final override { return 0; }
|
||||
|
||||
private:
|
||||
|
||||
@@ -51,11 +51,6 @@ public:
|
||||
void detach(Stream* stream) noexcept final override {}
|
||||
void updateTexImage(Stream* stream, int64_t* timestamp) noexcept final override {}
|
||||
|
||||
ExternalTexture* createExternalTextureStorage() noexcept final override { return nullptr; }
|
||||
void reallocateExternalStorage(ExternalTexture* ets,
|
||||
uint32_t w, uint32_t h, TextureFormat format) noexcept final override { }
|
||||
void destroyExternalTextureStorage(ExternalTexture* ets) noexcept final override { }
|
||||
|
||||
int getOSVersion() const noexcept final override { return 0; }
|
||||
|
||||
private:
|
||||
|
||||
@@ -52,11 +52,6 @@ public:
|
||||
void detach(Stream* stream) noexcept final override {}
|
||||
void updateTexImage(Stream* stream, int64_t* timestamp) noexcept final override {}
|
||||
|
||||
ExternalTexture* createExternalTextureStorage() noexcept final override { return nullptr; }
|
||||
void reallocateExternalStorage(ExternalTexture* ets,
|
||||
uint32_t w, uint32_t h, TextureFormat format) noexcept final override { }
|
||||
void destroyExternalTextureStorage(ExternalTexture* ets) noexcept final override { }
|
||||
|
||||
int getOSVersion() const noexcept final override { return 0; }
|
||||
};
|
||||
|
||||
|
||||
@@ -608,10 +608,6 @@ void VulkanDriver::createSwapChainHeadlessR(Handle<HwSwapChain> sch,
|
||||
construct<VulkanSwapChain>(sch, mContext, mStagePool, width, height);
|
||||
}
|
||||
|
||||
void VulkanDriver::createStreamFromTextureIdR(Handle<HwStream> sh, intptr_t externalTextureId,
|
||||
uint32_t width, uint32_t height) {
|
||||
}
|
||||
|
||||
void VulkanDriver::createTimerQueryR(Handle<HwTimerQuery> tqh, int) {
|
||||
// nothing to do, timer query was constructed in createTimerQueryS
|
||||
}
|
||||
@@ -678,10 +674,6 @@ Handle<HwSwapChain> VulkanDriver::createSwapChainHeadlessS() noexcept {
|
||||
return allocHandle<VulkanSwapChain>();
|
||||
}
|
||||
|
||||
Handle<HwStream> VulkanDriver::createStreamFromTextureIdS() noexcept {
|
||||
return {};
|
||||
}
|
||||
|
||||
Handle<HwTimerQuery> VulkanDriver::createTimerQueryS() noexcept {
|
||||
// The handle must be constructed here, as a synchronous call to getTimerQueryValue might happen
|
||||
// before createTimerQueryR is executed.
|
||||
@@ -1629,11 +1621,6 @@ void VulkanDriver::readPixels(Handle<HwRenderTarget> src, uint32_t x, uint32_t y
|
||||
scheduleDestroy(std::move(pbd));
|
||||
}
|
||||
|
||||
void VulkanDriver::readStreamPixels(Handle<HwStream> sh, uint32_t x, uint32_t y, uint32_t width,
|
||||
uint32_t height, PixelBufferDescriptor&& p) {
|
||||
scheduleDestroy(std::move(p));
|
||||
}
|
||||
|
||||
void VulkanDriver::blit(TargetBufferFlags buffers, Handle<HwRenderTarget> dst, Viewport dstRect,
|
||||
Handle<HwRenderTarget> src, Viewport srcRect, SamplerMagFilter filter) {
|
||||
assert_invariant(mContext.currentRenderPass.renderPass == VK_NULL_HANDLE);
|
||||
|
||||
@@ -35,10 +35,9 @@ class Engine;
|
||||
/**
|
||||
* Stream is used to attach a video stream to a Filament `Texture`.
|
||||
*
|
||||
* Note that the `Stream` class is fairly Android centric. It supports three different
|
||||
* Note that the `Stream` class is fairly Android centric. It supports two different
|
||||
* configurations:
|
||||
*
|
||||
* - TEXTURE_ID...takes an OpenGL texture ID and incurs a copy
|
||||
* - ACQUIRED.....connects to an Android AHardwareBuffer
|
||||
* - NATIVE.......connects to an Android SurfaceTexture
|
||||
*
|
||||
@@ -67,10 +66,6 @@ class Engine;
|
||||
* - Filament invokes low-level graphics commands on the \em{driver thread}.
|
||||
* - The thread that calls `beginFrame` is called the \em{main thread}.
|
||||
*
|
||||
* The TEXTURE_ID configuration achieves synchronization automatically. In this mode, Filament
|
||||
* performs a copy on the main thread during `beginFrame` by blitting the external image into
|
||||
* an internal round-robin queue of images. This copy has a run-time cost.
|
||||
*
|
||||
* For ACQUIRED streams, there is no need to perform the copy because Filament explictly acquires
|
||||
* the stream, then releases it later via a callback function. This configuration is especially
|
||||
* useful when the Vulkan backend is enabled.
|
||||
@@ -97,7 +92,7 @@ public:
|
||||
* By default, Stream objects are ACQUIRED and must have external images pushed to them via
|
||||
* <pre>Stream::setAcquiredImage</pre>.
|
||||
*
|
||||
* To create a NATIVE or TEXTURE_ID stream, call one of the <pre>stream</pre> methods
|
||||
* To create a NATIVE stream, call one of the <pre>stream</pre> methods
|
||||
* on the builder.
|
||||
*/
|
||||
class Builder : public BuilderBase<BuilderDetails> {
|
||||
@@ -122,23 +117,6 @@ public:
|
||||
*/
|
||||
Builder& stream(void* stream) noexcept;
|
||||
|
||||
/**
|
||||
* Creates a TEXTURE_ID stream. This will sample data from the supplied
|
||||
* external texture and copy it into an internal private texture.
|
||||
*
|
||||
* @param externalTextureId An opaque texture id (typically a GLuint created with glGenTextures)
|
||||
* In a context shared with filament. In that case this texture's
|
||||
* target must be GL_TEXTURE_EXTERNAL_OES and the wrap mode must
|
||||
* be CLAMP_TO_EDGE.
|
||||
*
|
||||
* @return This Builder, for chaining calls.
|
||||
*
|
||||
* @see Texture::setExternalStream()
|
||||
* @deprecated this method existed only for ARCore which doesn't need this anymore, use Texture::import() instead.
|
||||
*/
|
||||
UTILS_DEPRECATED
|
||||
Builder& stream(intptr_t externalTextureId) noexcept;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param width initial width of the incoming stream. Whether this value is used is
|
||||
@@ -173,7 +151,7 @@ public:
|
||||
};
|
||||
|
||||
/**
|
||||
* Indicates whether this stream is a NATIVE stream, TEXTURE_ID stream, or ACQUIRED stream.
|
||||
* Indicates whether this stream is a NATIVE stream or ACQUIRED stream.
|
||||
*/
|
||||
StreamType getStreamType() const noexcept;
|
||||
|
||||
@@ -190,7 +168,7 @@ public:
|
||||
* also where the callback is invoked. This method can only be used for streams that were
|
||||
* constructed without calling the `stream` method on the builder.
|
||||
*
|
||||
* @see Stream for more information about NATIVE, TEXTURE_ID, and ACQUIRED configurations.
|
||||
* @see Stream for more information about NATIVE and ACQUIRED configurations.
|
||||
*
|
||||
* @param image Pointer to AHardwareBuffer, casted to void* since this is a public header.
|
||||
* @param callback This is triggered by Filament when it wishes to release the image.
|
||||
@@ -222,63 +200,6 @@ public:
|
||||
*/
|
||||
void setDimensions(uint32_t width, uint32_t height) noexcept;
|
||||
|
||||
/**
|
||||
* Read-back the content of the last frame of a Stream since the last call to
|
||||
* Renderer.beginFrame().
|
||||
*
|
||||
* The Stream must be of type externalTextureId. This function is a no-op otherwise.
|
||||
*
|
||||
* @param xoffset Left offset of the sub-region to read back.
|
||||
* @param yoffset Bottom offset of the sub-region to read back.
|
||||
* @param width Width of the sub-region to read back.
|
||||
* @param height Height of the sub-region to read back.
|
||||
* @param buffer Client-side buffer where the read-back will be written.
|
||||
*
|
||||
* The following format are always supported:
|
||||
* - PixelBufferDescriptor::PixelDataFormat::RGBA
|
||||
* - PixelBufferDescriptor::PixelDataFormat::RGBA_INTEGER
|
||||
*
|
||||
* The following types are always supported:
|
||||
* - PixelBufferDescriptor::PixelDataType::UBYTE
|
||||
* - PixelBufferDescriptor::PixelDataType::UINT
|
||||
* - PixelBufferDescriptor::PixelDataType::INT
|
||||
* - PixelBufferDescriptor::PixelDataType::FLOAT
|
||||
*
|
||||
* Other combination of format/type may be supported. If a combination is
|
||||
* not supported, this operation may fail silently. Use a DEBUG build
|
||||
* to get some logs about the failure.
|
||||
*
|
||||
* Stream buffer User buffer (PixelBufferDescriptor&)
|
||||
* +--------------------+
|
||||
* | | .stride .alignment
|
||||
* | | ----------------------->-->
|
||||
* | | O----------------------+--+ low addresses
|
||||
* | | | | | |
|
||||
* | w | | | .top | |
|
||||
* | <---------> | | V | |
|
||||
* | +---------+ | | +---------+ | |
|
||||
* | | ^ | | ======> | | | | |
|
||||
* | x | h| | | |.left| | | |
|
||||
* +------>| v | | +---->| | | |
|
||||
* | +.........+ | | +.........+ | |
|
||||
* | ^ | | | |
|
||||
* | y | | +----------------------+--+ high addresses
|
||||
* O------------+-------+
|
||||
*
|
||||
* Typically readPixels() will be called after Renderer.beginFrame().
|
||||
*
|
||||
* After issuing this method, the callback associated with `buffer` will be invoked on the
|
||||
* main thread, indicating that the read-back has completed. Typically, this will happen
|
||||
* after multiple calls to beginFrame(), render(), endFrame().
|
||||
*
|
||||
* It is also possible to use a Fence to wait for the read-back.
|
||||
*
|
||||
* @remark
|
||||
* readPixels() is intended for debugging and testing. It will impact performance significantly.
|
||||
*/
|
||||
void readPixels(uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height,
|
||||
backend::PixelBufferDescriptor&& buffer) noexcept;
|
||||
|
||||
/**
|
||||
* Returns the presentation time of the currently displayed frame in nanosecond.
|
||||
*
|
||||
|
||||
@@ -36,11 +36,6 @@ void Stream::setDimensions(uint32_t width, uint32_t height) noexcept {
|
||||
upcast(this)->setDimensions(width, height);
|
||||
}
|
||||
|
||||
void Stream::readPixels(uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height,
|
||||
backend::PixelBufferDescriptor&& buffer) noexcept {
|
||||
upcast(this)->readPixels(xoffset, yoffset, width, height, std::move(buffer));
|
||||
}
|
||||
|
||||
int64_t Stream::getTimestamp() const noexcept {
|
||||
return upcast(this)->getTimestamp();
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ using namespace backend;
|
||||
|
||||
struct Stream::BuilderDetails {
|
||||
void* mStream = nullptr;
|
||||
intptr_t mExternalTextureId = 0;
|
||||
uint32_t mWidth = 0;
|
||||
uint32_t mHeight = 0;
|
||||
};
|
||||
@@ -52,11 +51,6 @@ Stream::Builder& Stream::Builder::stream(void* stream) noexcept {
|
||||
return *this;
|
||||
}
|
||||
|
||||
Stream::Builder& Stream::Builder::stream(intptr_t externalTextureId) noexcept {
|
||||
mImpl->mExternalTextureId = externalTextureId;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Stream::Builder& Stream::Builder::width(uint32_t width) noexcept {
|
||||
mImpl->mWidth = width;
|
||||
return *this;
|
||||
@@ -68,11 +62,6 @@ Stream::Builder& Stream::Builder::height(uint32_t height) noexcept {
|
||||
}
|
||||
|
||||
Stream* Stream::Builder::build(Engine& engine) {
|
||||
if (!ASSERT_PRECONDITION_NON_FATAL(!mImpl->mStream || !mImpl->mExternalTextureId,
|
||||
"One and only one of the stream or external texture can be specified")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return upcast(engine).createStream(*this);
|
||||
}
|
||||
|
||||
@@ -80,21 +69,14 @@ Stream* Stream::Builder::build(Engine& engine) {
|
||||
|
||||
FStream::FStream(FEngine& engine, const Builder& builder) noexcept
|
||||
: mEngine(engine),
|
||||
mStreamType(
|
||||
builder->mExternalTextureId ? StreamType::TEXTURE_ID :
|
||||
(builder->mStream ? StreamType::NATIVE : StreamType::ACQUIRED)
|
||||
),
|
||||
mStreamType(builder->mStream ? StreamType::NATIVE : StreamType::ACQUIRED),
|
||||
mNativeStream(builder->mStream),
|
||||
mExternalTextureId(builder->mExternalTextureId),
|
||||
mWidth(builder->mWidth),
|
||||
mHeight(builder->mHeight) {
|
||||
|
||||
if (mNativeStream) {
|
||||
// Note: this is a synchronous call. On Android, this calls back into Java.
|
||||
mStreamHandle = engine.getDriverApi().createStreamNative(mNativeStream);
|
||||
} else if (mExternalTextureId) {
|
||||
mStreamHandle = engine.getDriverApi().createStreamFromTextureId(
|
||||
mExternalTextureId, mWidth, mHeight);
|
||||
} else {
|
||||
mStreamHandle = engine.getDriverApi().createStreamAcquired();
|
||||
}
|
||||
@@ -124,28 +106,6 @@ void FStream::setDimensions(uint32_t width, uint32_t height) noexcept {
|
||||
mEngine.getDriverApi().setStreamDimensions(mStreamHandle, mWidth, mHeight);
|
||||
}
|
||||
|
||||
void FStream::readPixels(uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height,
|
||||
backend::PixelBufferDescriptor&& buffer) noexcept {
|
||||
if (getStreamType() == StreamType::TEXTURE_ID) {
|
||||
// this works only on external texture id streams
|
||||
|
||||
const size_t sizeNeeded = PixelBufferDescriptor::computeDataSize(
|
||||
buffer.format, buffer.type,
|
||||
buffer.stride ? buffer.stride : width,
|
||||
buffer.top + height,
|
||||
buffer.alignment);
|
||||
|
||||
if (!ASSERT_POSTCONDITION_NON_FATAL(buffer.size >= sizeNeeded,
|
||||
"buffer.size too small %u bytes, needed %u bytes", buffer.size, sizeNeeded)) {
|
||||
return;
|
||||
}
|
||||
|
||||
FEngine::DriverApi& driver = mEngine.getDriverApi();
|
||||
driver.readStreamPixels(mStreamHandle,
|
||||
xoffset, yoffset, width, height, std::move(buffer));
|
||||
}
|
||||
}
|
||||
|
||||
int64_t FStream::getTimestamp() const noexcept {
|
||||
FEngine::DriverApi& driver = mEngine.getDriverApi();
|
||||
return driver.getStreamTimestamp(mStreamHandle);
|
||||
|
||||
@@ -41,9 +41,6 @@ public:
|
||||
|
||||
void setDimensions(uint32_t width, uint32_t height) noexcept;
|
||||
|
||||
void readPixels(uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height,
|
||||
backend::PixelBufferDescriptor&& buffer) noexcept;
|
||||
|
||||
StreamType getStreamType() const noexcept { return mStreamType; }
|
||||
|
||||
uint32_t getWidth() const noexcept { return mWidth; }
|
||||
@@ -57,7 +54,6 @@ private:
|
||||
const StreamType mStreamType;
|
||||
backend::Handle<backend::HwStream> mStreamHandle;
|
||||
void* mNativeStream = nullptr;
|
||||
intptr_t mExternalTextureId;
|
||||
uint32_t mWidth;
|
||||
uint32_t mHeight;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user