【问题标题】:How to read OpenGL pixels in a separate thread using Processing?如何使用处理在单独的线程中读取 OpenGL 像素?
【发布时间】:2019-06-27 11:32:48
【问题描述】:

我正在尝试在单独的线程中从处理草图中渲染帧。 处理有一个loadPixels() 函数。问题在于 OpenGL 渲染器(P2DP3D 在处理中。):PGraphicsOpenGL loadPixels()

这是我的示例草图:

void setup(){
  size(300,300,P2D);
  noFill();
  background(255);
  rectMode(CENTER);
  stroke(0,32);
  smooth(8);
  // instantiate and start rendering thread
  new PNGRenderer(this);
}

void draw(){
  // draw moving shapes
  translate(width * 0.5, height * 0.5);
  rotate(sin(frameCount * 0.075));
  scale(sin(frameCount * 0.01));
  translate(cos(frameCount * 0.01) * width * 0.1,sin(frameCount * 0.01) * height * 0.1);
  rect(0,0,width * .9,height * .9);
}

public class PNGRenderer implements Runnable{

  PApplet parent;
  PImage  frame;
  boolean shouldSave = false;

  int savedFrameCount;

  boolean isRunning = true;

  PNGRenderer(PApplet parent){
    this.parent = parent;
    this.parent.registerMethod("draw",this);

    frame = createImage(parent.width,parent.height,ARGB);
    frame.loadPixels();

    Thread renderThread = new Thread(this);
    renderThread.setName("Renderer-Thread");
    renderThread.start();
  }

  public void draw(){
    // all is well if I sample pixels in the same OpenGL thread
    //parent.loadPixels();
    shouldSave = true;
  } 

  synchronized void sampleAndSavePixels(){
    if(shouldSave){
      // program crashes if I try to save in a separate thread
      parent.loadPixels();
      arrayCopy(parent.pixels,frame.pixels);
      frame.updatePixels();
      frame.save(dataPath("frames/frame_"+nf(savedFrameCount++,4)+".png"));
      println("saved frame",savedFrameCount);
      shouldSave = false;
    }
  }

  public void run(){
    while(isRunning){
      sampleAndSavePixels();
    }
  }

}

据我所知(到目前为止,我还不是 OpenGL 向导)读取像素需要在同一个 OpenGL 线程中完成。这是我试图避免的减速。

我确实在 stackoverflow 和其他论坛上看过类似的帖子:

据我了解,我需要在我的渲染器线程中创建一个单独的 OpenGL 上下文,并将 Processing 的 OpenGL 线程中的纹理/缓冲区共享给我。我目前不确定语法。

这可能是 RTFM 的情况,但请您指出 Java OpenGL 在单独线程中读取像素的方向(可以是纯 Java,不一定使用处理)?

【问题讨论】:

  • OpenGL Context 是线程本地的。上下文必须在线程中设置为“当前”。问题是如何在处理中做到这一点。
  • @Rabbid76 如果我错了请纠正我,我理解的方式是:我会在我的线程中创建单独的 OpenGL 上下文,并且对于每一帧首先暂停处理的动画线程,然后使渲染器线程的OpenGL 上下文当前,以某种方式将缓冲区从处理上下文复制到渲染器上下文中,恢复动画线程,而渲染器线程从渲染器线程中复制的缓冲区“下载”/读取像素并保存帧?
  • 您应该在 JogAmp 官方论坛上提出这个问题。你想达到什么目的?
  • @gouessej 我正在尝试保存使用处理生成的动画的 png 序列。我已经分析了我的代码,并且 1080p 帧速率从 ~25 下降到 ~15fps。这还不错,但是在分析 CPU 使用情况后,我看到 loadPixels() 需要花费好几毫秒才能完成。我想将该操作移到一个单独的线程中,但是看起来我需要跳过一些 GL 箍 :) Gernot 的建议听起来不错。你有我应该尝试的想法吗? :D
  • 使用 com.jogamp.opengl.util.GLReadBufferUtil:jogamp.org/deployment/jogamp-next/javadoc/jogl/javadoc/com/…

标签: java multithreading opengl processing jogl


【解决方案1】:

OpenGL Context 是线程本地的。上下文必须在线程中设置为“当前”。不同的线程可以使用相同的上下文,但一个上下文不能同时在多个线程中是当前的。

您必须确保线程不会同时使用相同的上下文。当然,您可以为不同的线程创建不同的上下文,并将一个上下文共享给另一个。
OPENGL MULTI-CONTEXT

但请注意,GPU 已经并行运行。在不同线程中使用 1 个 GPU 没有任何好处。 GPU一次只能处理1个线程的指令。当然Rendering Pipeline的每个阶段处理顶点、片段等都是并行的

【讨论】:

  • 谢谢(+1)。如果我理解正确,我可以从我的渲染器线程中使用 P2D 的 OpenGL 上下文,但我需要在 P2D 中将其设置为“非活动”,并在我的线程中设置为“当前/活动”,读取像素,然后在 P2D 线程中将上下文设为当前再次 ?如果是这种情况,当我从我的线程 loadPixels() 时,渲染是否不必在 P2D 渲染器上暂停,从而破坏了在单独线程中读取像素的目的?我不是 100% 确定我明白这就是为什么我要和你仔细检查:)
  • @GeorgeProfenza 上下文不能同时在多个线程中处于当前状态。 “当我从我的线程 loadPixels() 时,渲染是否不必在 P2D 渲染器上暂停,从而破坏了在单独线程中读取像素的目的?” - 是的。请注意,帧缓冲区是上下文的对象。 OpenGL 有一个指令缓存(每个上下文),只能同时处理 1 条指令。由于 OpenGL 是一个状态引擎(例如,当前帧缓冲区是一个状态),因此指令必须具有明确定义的顺序。
  • 这是一个(不知情的)想法/问题:我能否使用两个 OpenGL 上下文(P2D,线程),将 GPU 缓冲区从 P2D 复制到我的线程,然后让我的线程从重复缓冲区? (我的“我-我-这--过于复杂-?”感觉刺痛:))))
  • @GeorgeProfenza 我认为您想提高性能。这个想法可能会奏效。但我不知道如何在处理中做到这一点。我会知道如何在原生 OpenGL 中做到这一点。
  • 你能分享一个基本的 OpenGL sn-p 吗?我会通过 PGL 找到自己的方式:D
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-02-22
  • 2019-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多