Commit ddff9231 authored by Radek Ošlejšek's avatar Radek Ošlejšek
Browse files

Merge branch '377-Distribute-updated-GPU-API' into 'master'

Resolve "Use the new GPU buffer implementation across application and provide tests"

Closes #377

See merge request grp-fidentis/analyst2!438
parents 1ea4988e f546ad33
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@ import cz.fidentis.analyst.data.landmarks.Landmark;
import cz.fidentis.analyst.data.mesh.measurement.*;
import cz.fidentis.analyst.engines.distance.MeshDistanceConfig;
import cz.fidentis.analyst.engines.distance.MeshDistanceVisitor;
import cz.fidentis.analyst.engines.distance.impl.MeshDistanceNNGPU;
import cz.fidentis.analyst.engines.face.FaceDistanceServices;
import cz.fidentis.analyst.engines.face.FaceStateServices;

@@ -74,6 +75,10 @@ public class FaceDistanceServicesImpl {

        secondaryFace.getMeshModel().compute(distVisitor);

        if (distVisitor instanceof MeshDistanceNNGPU meshDistanceNNGPU) {
            meshDistanceNNGPU.readData();
        }

        distVisitor.dispose();

        return distVisitor.getDistancesOfVisitedFacets();
+0 −65
Original line number Diff line number Diff line
package cz.fidentis.analyst.opencl.memory;

import com.jogamp.opencl.CLContext;
import cz.fidentis.analyst.data.mesh.MeshTriangle;
import cz.fidentis.analyst.opencl.memory.impl.IntegerBuffer;
import cz.fidentis.analyst.opencl.memory.impl.MeshTriangleBuffer;
import cz.fidentis.analyst.opencl.memory.impl.RayIntersectionBuffer;
import cz.fidentis.analyst.opencl.memory.impl.VoxelBuffer;

import javax.vecmath.Point3d;
import javax.vecmath.Vector3d;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;

/**
 * Factory for OpenCL buffers with additional functionality
 *
 * @author Marek Horský
 */
public interface BufferFactory {
    /**
     * Creates resizable {@link IntegerBuffer}
     *
     * @return IntegerBuffer
     */
    static BufferGPU<IntBuffer> getIntBuffer(CLContext clContext) {
        return new IntegerBuffer(clContext);
    }

    /**
     * Creates resizable {@link VoxelBuffer}
     *
     * @return VoxelBuffer
     */
    static WriteBufferGPU<Point3d> getVoxelPointBuffer(CLContext context) {
        return new VoxelBuffer<>(context);
    }

    /**
     * Creates resizable {@link VoxelBuffer}
     *
     * @return VoxelBuffer
     */
    static WriteBufferGPU<Vector3d> getVoxelVectorBuffer(CLContext context) {
        return new VoxelBuffer<>(context);
    }

    /**
     * Creates resizable {@link RayIntersectionBuffer} to receive intersections calculate on GPU
     *
     * @return RayIntersectionBuffer
     */
    static BufferGPU<FloatBuffer> getRayIntersectionBuffer(CLContext context) {
        return new RayIntersectionBuffer(context);
    }

    /**
     * Buffer to hold Mesh Triangles in GPU memory
     *
     * @return MeshTriangleBuffer
     */
    static WriteBufferGPU<MeshTriangle> getMeshTriangleBuffer(CLContext clContext) {
        return new MeshTriangleBuffer(clContext);
    }
}
+30 −90
Original line number Diff line number Diff line
package cz.fidentis.analyst.opencl.memory;

import com.jogamp.opencl.CLBuffer;
import com.jogamp.opencl.CLCommandQueue;
import com.jogamp.opencl.CLContext;
import com.jogamp.opencl.CLMemory;

import java.nio.Buffer;
import java.util.List;

/**
 * Buffer in GPU memory. Read-Only on host side.
 * Interface enclosing GPU Buffer. Specifies buffer-related methods.
 *
 * @param <T> Any type to be stored in buffer
 * @param <T> type of underlying buffer
 * @param <S> type of element stored in the buffer
 * @author Marek Horský
 */

public abstract class BufferGPU<T extends Buffer> implements CLResources {
    private final CLContext clContext;
    private final CLCommandQueue queue;
    private final int elementSize;
    private int count; // Number of elements within the buffer
    private int size; // Currently allocated memory
    protected final CLMemory.Mem memoryType;
    protected CLBuffer<T> buffer;
    protected CLBuffer<T> subBuffer;
public interface BufferGPU<T extends Buffer, S> extends CLResources {

    /**
     * Creates Buffer in specified OpenCl Context with default element size set to 1
     * Puts elements provided by supplier until null value is encountered.
     * This method does not populate original data, since we do not have any original data list.
     *
     * @param clContext OpenCl Context
     * @param supplier to provide elements
     */
    protected BufferGPU(CLContext clContext) {
        this(clContext, 1, CLMemory.Mem.READ_WRITE);
    }
    void putAll(BufferElementSupplier<S> supplier);

    /**
     * Creates Buffer in specified OpenCl Context with given element size
     *
     * @param clContext   OpenCl Context
     * @param elementSize element size
     * Populates buffer with desired elements.
     * Overwrites previous data and resizes itself, if needed.
     */
    protected BufferGPU(CLContext clContext, int elementSize, CLMemory.Mem memoryType) {
        this.clContext = clContext;
        this.queue = clContext.getMaxFlopsDevice().createCommandQueue();
        this.elementSize = elementSize;
        this.memoryType = memoryType;
    }

    @Override
    public void release() {
        this.buffer.release();
    }
    void putAll(List<S> points);

    /**
     * Some elements take multiple values to be continuously stored in buffer.
     * Reads desired number of elements from underlying gpu memory
     *
     * @return Size of 1 element loaded in buffer.
     * @param count number of elements to be read
     * @return list of elements read from gpu.
     */
    public int getElementSize() {
        return elementSize;
    }
    List<S> readElements(int count);

    /**
     * @return Count of the elements loaded inside. Do not confuse with the actual size of allocated memory
     */
    public int getCount() {
        return count;
    }
    int getCount();

    /**
     * @return Memory size of the buffer. Do not confuse with current element count
     */
    public int getSize() {
        return count * elementSize;
    }
    int getSize();

    /**
     * @return Memory size of a single element.
     */
    int getElementSize();

    /**
     * Get current OpenCL context
     *
     * @return OpenCL context
     */
    public CLContext getClContext() {
        return clContext;
    }
    CLContext getClContext();

    /**
     * Creating new buffer and releasing the old one is costly. Reuse them if they are already big enough.
     *
     * @param elementCount element count to fit in
     */
    public void resize(int elementCount) {
        int desiredSize = elementCount * elementSize;
        if (size < desiredSize) {
            this.size = desiredSize;
            allocateBuffer(desiredSize);
        }
        if (count != elementCount) {
            this.count = elementCount;
            resizeSubBuffer(desiredSize);
        }
    }
    void resize(int elementCount);

    /**
     * Get underlying CLBuffer
     *
     * @return CLBuffer
     */
    public CLBuffer<T> get(){
        return subBuffer;
    }
    CLBuffer<T> get();

    /**
     * Rewinds the buffer
     */
    public void rewind(){
        this.buffer.getBuffer().rewind();
        this.subBuffer.getBuffer().rewind();
    }

    /**
     * Allocate the buffer to fit the elements
     *
     * @param desiredSize desired size of the buffer
     */
    protected abstract void allocateBuffer(int desiredSize);
    void rewind();

    /**
     * Creating new SubBuffer of the main buffer to operate with smaller amount of memory
     * Gets the last loaded list of data
     *
     * @param desiredSize desired size of the buffer
     * @return list of last data loaded into the buffer
     */
    protected void resizeSubBuffer(int desiredSize){
        if (subBuffer != null && !subBuffer.isReleased()) {
            subBuffer.release();
        }
        subBuffer = buffer.createSubBuffer(0, desiredSize, memoryType);
    }

    /**
     * Get current OpenCL queue
     *
     * @return OpenCL queue
     */
    protected CLCommandQueue getQueue() {
        return queue;
    }
    List<S> getOriginalData();
}
+0 −54
Original line number Diff line number Diff line
package cz.fidentis.analyst.opencl.memory;

import com.jogamp.opencl.CLContext;
import com.jogamp.opencl.CLMemory;

import java.nio.FloatBuffer;
import java.util.List;

/**
 * Resizable buffer of GPU memory. Can be populated on host-side.
 *
 * @param <T> Any type to be stored in buffer
 * @author Marek Horský
 */
public abstract class WriteBufferGPU<T> extends BufferGPU<FloatBuffer> {

    /**
     * Creates Write Buffer in specified OpenCl Context with default element size set to 1
     *
     * @param clContext OpenCl Context
     */
    protected WriteBufferGPU(CLContext clContext) {
        super(clContext);
    }

    /**
     * Creates Write Buffer in specified OpenCl Context with given element size
     *
     * @param clContext OpenCl Context
     * @param elementSize element size
     */
    protected WriteBufferGPU(CLContext clContext, int elementSize) {
        super(clContext, elementSize, CLMemory.Mem.READ_WRITE);
    }

    /**
     * Copies contents to GPU
     */
    public abstract void writeToGPU();

    /**
     * Populated buffer with desired elements.
     * Overwrites previous data and resizes itself, if needed.
     * Is asynchronous! Make sure to call finish() method before use
     */
    public abstract void putAll(List<T> points);

    /**
     * Gets data, that are currently copied to GPU
     *
     * @return data
     */
    public abstract List<T> getOriginalData();
}
+47 −60
Original line number Diff line number Diff line
package cz.fidentis.analyst.opencl.memory;
package cz.fidentis.analyst.opencl.memory.impl;

import com.jogamp.opencl.CLBuffer;
import com.jogamp.opencl.CLCommandQueue;
import com.jogamp.opencl.CLContext;
import com.jogamp.opencl.CLMemory;
import cz.fidentis.analyst.opencl.memory.BufferElementSupplier;
import cz.fidentis.analyst.opencl.memory.BufferGPU;

import java.nio.Buffer;
import java.util.ArrayList;
import java.util.List;

/**
 * Resizable buffer of GPU memory. Provides host-side methods for writing and reading of elements.
 * Resizable buffer of GPU memory. Provides generic host-side methods for writing and reading of elements.
 *
 * @param <S> Type of underlying buffer
 * @param <T> Any type to be stored in buffer
 * @param <T> type of underlying buffer
 * @param <S> type of element stored in the buffer
 * @author Marek Horský
 */
public abstract class NewBufferGPU<T extends Buffer, S> implements CLResources {
abstract class AbstractBufferGPU<T extends Buffer, S> implements BufferGPU<T, S> {
    private final CLContext clContext;
    private final CLCommandQueue queue;
    private final int elementSize;
    private int count; // Number of elements within the buffer
    private int size; // Currently allocated memory
    protected CLBuffer<T> buffer;
    protected CLBuffer<T> subBuffer;
    private List<S> originalData = List.of();
    private CLBuffer<T> buffer;
    private CLBuffer<T> subBuffer;

    /**
     * Creates Buffer in specified OpenCl Context with given element size
@@ -31,7 +34,7 @@ public abstract class NewBufferGPU<T extends Buffer, S> implements CLResources {
     * @param clContext   OpenCl Context
     * @param elementSize element size
     */
    protected NewBufferGPU(CLContext clContext, int elementSize) {
    protected AbstractBufferGPU(CLContext clContext, int elementSize) {
        this.clContext = clContext;
        this.queue = clContext.getMaxFlopsDevice().createCommandQueue();
        this.elementSize = elementSize;
@@ -59,16 +62,26 @@ public abstract class NewBufferGPU<T extends Buffer, S> implements CLResources {
     */
    protected abstract void allocateBuffer(int desiredSize);

    /**
     * Sets GPU memory buffer.
     *
     * @param buffer buffer to be set
     */
    protected void setBuffer(CLBuffer<T> buffer) {
        this.buffer = buffer;
    }

    @Override
    public List<S> getOriginalData() {
        return originalData;
    }

    @Override
    public void release() {
        this.buffer.release();
    }

    /**
     * Puts elements provided by supplier until null value is encountered.
     *
     * @param supplier to provide elements
     */
    @Override
    public void putAll(BufferElementSupplier<S> supplier) {
        resize(supplier.getSize());
        rewind();
@@ -80,31 +93,24 @@ public abstract class NewBufferGPU<T extends Buffer, S> implements CLResources {
            putElement(element);
        }
        rewind();
        getQueue().putWriteBuffer(subBuffer, false)
        queue.putWriteBuffer(subBuffer, false)
                .finish();
    }

    /**
     * Populates buffer with desired elements.
     * Overwrites previous data and resizes itself, if needed.
     */
    @Override
    public void putAll(List<S> points) {
        this.originalData = points;
        resize(points.size());
        rewind();
        points.forEach(this::putElement);
        rewind();
        getQueue().putWriteBuffer(subBuffer, false)
        queue.putWriteBuffer(subBuffer, false)
                .finish();
    }

    /**
     * Reads desired number of elements from underlying gpu memory
     *
     * @param count number of elements to be read
     * @return list of elements read from gpu.
     */
    @Override
    public List<S> readElements(int count) {
        getQueue().putReadBuffer(subBuffer, false)
        queue.putReadBuffer(subBuffer, false)
                .finish();
        rewind();
        ArrayList<S> result = new ArrayList<>(count);
@@ -115,38 +121,34 @@ public abstract class NewBufferGPU<T extends Buffer, S> implements CLResources {
        return result;
    }

    /**
     * @return Count of the elements loaded inside. Do not confuse with the actual size of allocated memory
     */
    @Override
    public int getCount() {
        return count;
    }

    /**
     * @return Memory size of the buffer. Do not confuse with current element count
     */
    @Override
    public int getSize() {
        return count * elementSize;
    }

    /**
     * Get current OpenCL context
     *
     * @return OpenCL context
     */
    @Override
    public int getElementSize() {
        return elementSize;
    }

    @Override
    public CLContext getClContext() {
        return clContext;
    }

    /**
     * Creating new buffer and releasing the old one is costly. Reuse them if they are already big enough.
     *
     * @param elementCount element count to fit in
     */
    @Override
    public void resize(int elementCount) {
        int desiredSize = elementCount * elementSize;
        if (size < desiredSize) {
            this.size = desiredSize;
            if (buffer != null) {
                release();
            }
            allocateBuffer(desiredSize);
        }
        if (count != elementCount) {
@@ -155,18 +157,12 @@ public abstract class NewBufferGPU<T extends Buffer, S> implements CLResources {
        }
    }

    /**
     * Get underlying CLBuffer
     *
     * @return CLBuffer
     */
    @Override
    public CLBuffer<T> get() {
        return subBuffer;
    }

    /**
     * Rewinds the buffer
     */
    @Override
    public void rewind() {
        this.buffer.getBuffer().rewind();
        this.subBuffer.getBuffer().rewind();
@@ -177,19 +173,10 @@ public abstract class NewBufferGPU<T extends Buffer, S> implements CLResources {
     *
     * @param desiredSize desired size of the buffer
     */
    protected void resizeSubBuffer(int desiredSize) {
    private void resizeSubBuffer(int desiredSize) {
        if (subBuffer != null && !subBuffer.isReleased()) {
            subBuffer.release();
        }
        subBuffer = buffer.createSubBuffer(0, desiredSize, CLMemory.Mem.READ_WRITE);
    }

    /**
     * Get current OpenCL queue
     *
     * @return OpenCL queue
     */
    protected CLCommandQueue getQueue() {
        return queue;
    }
}
Loading