Commit f546ad33 authored by Marek Horský's avatar Marek Horský Committed by Radek Ošlejšek
Browse files

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

parent 1ea4988e
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