- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在使用 GLSurfaceView 创建自定义相机预览,使用 OpenGl 渲染相机提供给我的帧。我已经完全实现了相机并按照我期望的方式工作()
使用 GLES20.glReadPixels() 我发现有些设备会出现 fps 丢失,这主要是屏幕分辨率较高的设备,这是有道理的,因为 glReadPixels 需要读取更多分辨率更高的像素。
我做了一些挖掘,发现其他人对 glReadPixels 也有类似的问题,许多人建议使用 PBO,最好使用其中两个充当双缓冲区,这样我就可以读取像素数据而不会阻塞/停止当前的渲染过程。我完全理解双缓冲的概念,我是 OpenGL 的新手,需要一些关于如何让双缓冲 PBO 工作的指导。
我找到了一些 PBO 双缓冲的解决方案,但我永远找不到一个完整的解决方案来完全理解它如何与 GLES 交互。
我对 GLSurfaceView.Renderer.onDrawFrame() 的实现
// mBuffer and mBitmap are declared and allocated outside of the onDrawFrame Method
// Buffer is used to store pixel data from glReadPixels
mBuffer.rewind();
GLES20.glUseProgram(hProgram);
if (tex_matrix != null)
{
GLES20.glUniformMatrix4fv(muTexMatrixLoc, 1, false, tex_matrix, 0);
}
GLES20.glUniformMatrix4fv(muMVPMatrixLoc, 1, false, mMvpMatrix, 0);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, tex_id);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, GLConstants.VERTEX_NUM);
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
// Read pixels from the current GLES context
GLES10.glReadPixels(0, 0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, mBuffer);
// Copy the Pixels from the buffer
mBitmap.copyPixelsFromBuffer(mBuffer);
GLES20.glUseProgram(0);
最佳答案
经过大量研究和挖掘,我找到了 glReadPixels 的解决方案以及如何使用 PBO 缓冲图像/帧以供以后处理。
所以我们需要做的第一件事就是在 GLES2 中公开一个额外的功能。在您的应用程序模块中添加一个名为 cpp 的新目录,然后创建一个名为 GlesHelper 的新 c 文件(或者您想要的任何名称)
并粘贴以下代码:
#include <jni.h>
#include <GLES2/gl2.h>
JNIEXPORT void JNICALL
// Change
Java_com_your_full_package_name_helper_GlesHelper_glReadPixels(JNIEnv *env, jobject instance, jint x,
jint y, jint width, jint height,
jint format, jint type) {
// TODO
glReadPixels(x, y, width, height, format, type, 0);
}
然后我们需要将 CMakeFile 添加到项目的根目录。右键,新建文件,输入CMakeLists.txt
并粘贴以下代码
cmake_minimum_required(VERSION 3.4.1)
add_library( # Specifies the name of the library.
native-lib
# Sets the library as a shared library.
SHARED
# Provides a relative path to your source file(s).
src/main//cpp//GlesHelper.c )
target_link_libraries( # Specifies the target library.
native-lib
# Links the target library to the log library
# included in the NDK.
${log-lib}
GLESv2)
现在打开你的 app/modules build.gradle 文件
将其粘贴到 Gradle 文件的 android.defaultConfig 部分
externalNativeBuild {
// Encapsulates your CMake build configurations.
cmake {
// Provides a relative path to your CMake build script.
cppFlags "-std=c++11 -fexceptions"
arguments "-DANDROID_STL=c++_shared"
}
}
然后将其粘贴到 Gradle 文件的 android 部分
externalNativeBuild {
// Encapsulates your CMake build configurations.
cmake {
// Provides a relative path to your CMake build script.
path "CMakeLists.txt"
}
}
这就是所有的 MakeFile 和 c 的东西所有设置让我们转移到一些 java
在您的项目中创建一个与 c 文件中的包相匹配的新文件,即com_your_full_package_name_helper = com.your.full.package.name.helper
确保这些正确匹配,与类名和函数名相同。
所以你的类应该是这样的
package com.your.full.package.name.helper;
public class GlesHelper
{
public static native void glReadPixels(int x, int y, int width, int height, int format, int type);
}
因为我们已经将 native 代码添加到项目中,所以我们需要使用 System.loadLibrary("native-lib") 来加载我们的新方法。
在我们开始下一步之前,将这些成员变量添加到您的渲染器
/**
* The PBO Ids, increase the allocate amount for more PBO's
* The more PBO's the smoother the frame rate (to an extent)
* Side affect of having more PBO's the frames you get from the PBO's will lag behind by the amount of pbo's
*/
private IntBuffer mPboIds = IntBuffer.allocate(2);;
/**
* The current PBO Index
*/
private int mCurrentPboIndex = 0;
/**
* The next PBO Index
*/
private int mNextPboIndex = 1;
所以现在我们需要初始化我们的 PBO,这非常简单
// Generate the buffers for the pbo's
GLES30.glGenBuffers(mPboIds.capacity(), mPboIds);
// Loop for how many pbo's we have
for (int i = 0; i < mPboIds.capacity(); i++)
{
// Bind the Pixel_Pack_Buffer to the current pbo id
GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, mPboIds.get(i));
// Buffer empty data, capacity is the width * height * 4
GLES30.glBufferData(GLES30.GL_PIXEL_PACK_BUFFER, capacity, null, GLES30.GL_STATIC_READ);
}
// Reset the current buffer so we can draw properly
GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, 0);
然后在我们开始绘图之前调用此方法,这会将像素数据读入 pbo、交换缓冲区并让您访问像素数据。
/**
* Reads the pixels from the PBO and swaps the buffers
*/
private void readPixelsFromPBO()
{
// Bind the current buffer
GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, mPboIds.get(mCurrentPboIndex));
// Read pixels into the bound buffer
GlesHelper.glReadPixels(0, 0, mViewWidth, mViewHeight, GLES20.GL_RGBA, GLES30.GL_UNSIGNED_BYTE);
// Bind the next buffer
GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, mPboIds.get(mNextPboIndex));
// Map to buffer to a byte buffer, this is our pixel data
ByteBuffer pixelsBuffer = (ByteBuffer) GLES30.glMapBufferRange(GLES30.GL_PIXEL_PACK_BUFFER, 0, mViewWidth * mViewHeight * 4, GLES30.GL_MAP_READ_BIT);
if(mSkipFirstFrame)
{
// Skip the first frame as the PBO's have nothing in them until the second render cycle
}
// Set skip first frame to true so we can begin frame processing
mSkipFirstFrame = true;
// Swap the buffer index
mCurrentPboIndex = (mCurrentPboIndex + 1) % mPboIds.capacity();
mNextPboIndex = (mNextPboIndex + 1) % mPboIds.capacity();
// Unmap the buffers
GLES30.glUnmapBuffer(GLES30.GL_PIXEL_PACK_BUFFER);
GLES30.glBindBuffer(GLES30.GL_PIXEL_PACK_BUFFER, GLES20.GL_NONE);
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, GLES20.GL_NONE);
}
所以回到我最初的问题,我们的 Redner/onDrawMethod 看起来像这样。
// Use the OpenGL Program for rendering
GLES20.glUseProgram(mProgram);
// If the Texture Matrix is not null
if (textureMatrix != null)
{
// Apply the Matrix
GLES20.glUniformMatrix4fv(mTexMatrixLoc, 1, false, textureMatrix, 0);
}
// Apply the Matrix
GLES20.glUniformMatrix4fv(mMVPMatrixLoc, 1, false, mMvpMatrix, 0);
// Bind the Texture
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textureID);
// Draw the texture
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, GLConstants.VERTEX_NUM);
// Unbind the Texture
GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
// Read from PBO
readPixelsFromPBO()
我希望这可以帮助那些对 glReadPixels 的性能有类似问题或至少努力实现 PBO 的人
关于android - glReadPixels 很慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56379809/
我有一个 view我拖了一个UITableView在里面,还有 2 UIImageView s(第一个显示背景图像,第二个只是在 View 顶部显示一个非常小的标题和图像)。 它们都设置为 weak特
我尝试用 C# 编写简单的 PostgreSQL 查询。第一个 connection.open() 需要 20 秒。其他连接立即执行。 PGAdmin 工作也很慢。如果我打开“查看所有行”,它也需要大
我制作了一个 html5 视频播放器,我注意到如果当前播放的视频有点大,搜索时间会异常地长。 越接近终点,寻找的时间越长;独立于我之前是否去过那里/与当前时间点的距离有多近,或者我是否缓冲了整个视频。
我正在使用 MaterialDatePicker,但速度很慢。 public class MainActivity extends AppCompatActivity { MaterialDa
我想知道为什么 MyBatis 是 慢 在我的应用程序中。 对于 SELECT COUNT(*) ,所用时间为: 20 秒 - 第一个请求 2-3 秒 - 后续请求 缓存很可能使后续请求更快。 配置
我已经安装了一个默认的开箱即用的 FreeSwitch 实例,但是当我尝试进行内部调用(分机到分机)时,大约需要 12 秒才能建立调用并且我可以听到铃声。 当我查看日志时,我几乎立即看到了连接请求,但
我已经放弃了让它跑得更快的实际尝试。 我最大的问题是,当我插入 html 时,应用程序会变慢到爬行。我有一个进度条,我正在调用 QCoreApplication.processEvents() (顺便
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 9
Doxygen 在我们的代码库上运行大约需要 12 个小时。这主要是因为有很多代码要处理(约 1.5M 行)。然而,它很快就会接近我们无法进行夜间文档更新的地步,因为它们需要太长时间。我们已经不得不减
我正在重写我的旧渲染管道。我根据自己的喜好创建了一个非常精简的原型(prototype),令我震惊的是,我原来相当复杂且优化不佳的管道与 super 简单的原型(prototype)具有完全相同的性能
我想为我的网站使用 Gridster,但我需要使用“add_widget”命令添加很多小部件。我做了一个测试,我认为“add_widget”功能存在问题:网格越来越慢并且存在内存泄漏。 您可以在此视频
我有一份包含图表和表格的报告。 我正在使用 html2canvas与 jsPDF将此报告导出为 PDF 文件。 但是这个过程耗时很长,超过11000ms。 我尝试更改格式和质量,但没有任何效果。 请看
我正在查询大于时间戳的类的所有修订,使用: AuditReaderFactory .get(emf.createEntityManager()) .createQuery().forR
我最近想加速一个加密系统。而在这个系统中,它将使用mysql,因此它包括文件。 而且我发现系统运行缓慢并不是因为加解密,而是因为处理一些sql语句。 它将在运行时使用内存数据库,并使用 中的 mys
谁能看出为什么这需要大约 20 秒?我正在运行下面的代码以将 JSON 请求发布到本地服务器 192.168.1.127。 curl -H "Content-type: application/jso
我有两个表:Posts 和Tags,其中存储了用户发布的文章以及他们为文章附加的标签。 PostTags 表用于表示文章 ID 和标签 ID 的关系。结构如下: 帖子: id | title | au
一个我应该能够自己回答但我没有,而且在谷歌中也找不到任何答案的问题: 我有一个表,其中包含具有以下结构的 500 万行: CREATE TABLE IF NOT EXISTS `files_histo
以下查询在具有大约 50 万行的表上执行需要 20 多秒: SELECT images.id, images.user_id, images_locale.filename, extension, s
我正在使用 $.getJSON 来提取对象 list (100 个项目,不是一个大集合),但 XHR 调用需要 8-10 秒。 想了解我是否缺少某些内容或我可以采取哪些措施来加快我的计划? 最佳答案
在这段代码中,我从网站获取一个字符串并将其显示在标签上。在标签上显示字符串真的很慢!大约 10 秒。但是在控制台 println (date) 上打印字符串时是立即的。我该如何解决这个问题?
我是一名优秀的程序员,十分优秀!