9.8. イメージの読み込みと書き込み

9.8.1. clEnqueueReadImageとclEnqueueWriteImage

clEnqueueReadImage関数はイメージオブジェクトまたはイメージ配列オブジェクトからホストメモリに読み込むコマンドを挿入します。

注記

詳しくは「表:clEnqueueReadImageとclEnqueueWriteImage」(表B.44「表:clEnqueueReadImageとclEnqueueWriteImage」)を参照ください。

関数の定義は以下のようになります。

int org.jocl.CL.clEnqueueReadImage(
    cl_command_queue command_queue, //(1)
    cl_mem image, //(2)
    boolean blocking_read, //(3)
    long[] origin, //(4)
    long[] region, //(5)
    long row_pitch, //(6)
    long slice_pitch, //(7)
    Pointer ptr, //(8)
    int num_events_in_wait_list, //(9)
    cl_event[] event_wait_list, //(10)
    cl_event event) //(11)

(1)

読み込みコマンドを挿入するコマンドキューを指定。command_queueとimageは同じOpenCLコンテキスト上で生成される必要がある。

(2)

有効なイメージオブジェクトまたはイメージ配列オブジェクトを指定します。

(3)

読み込み操作をブロッキング、またはノンブロッキングで行うのかを指定。blocking_readにCL_TRUEを指定すると、読み込みコマンドはブロッキングとなり、バッファデータを読み込んでptrが指すメモリ領域に複製し終わるまで、clEnqueueReadImageは戻らない。

(4)

読み込みを行うイメージ内での (x, y, z) オフセットをピクセルで指定。image が2Dイメージオブジェクトであるとき、origin[2] で指定する z 値は0でなければなりません。

(5)

1D、2D、3D矩形領域の(width, height, depth) をピクセルで定義。 2D矩形領域の(width, height)をピクセルで定義し、2Dイメージ配列のイメージ個数の定義。1D矩形領域の(width)をピクセルで定義し、1Dイメージ配列のイメージ個数を定義。

(6)

各行が使用する長さをバイトで指定。この値は、画素のバイトサイズ*width以上となる必要がある。row_pitchに0を設定すると、画素のバイトサイズ*widthに基づいて適切な長さが計算される。

(7)

読み込み、または書き込まれる3Dイメージ内の3D領域の各2Dスライス、または1Dまたは2Dイメージ配列の各イメージが使用する長さを指定(バイトで表す)。 イメージが1Dまたは2Dの場合は、この引数は0となります。

(8)

読み込むイメージデータの保存先となるホストメモリバッファへのポインタを指定。

(9)

event_wait_listで指定したイベントオブジェクトの数を指定。

(10)

このコマンドが実行される前に完了されているイベントを指定

(11)

読み込みコマンドを識別するイベントオブジェクトが戻され、コマンド完了の確認やコマンド完了の待機に使える。

clEnqueueWriteImage関数はホストメモリからイメージオブジェクトまたはイメージ配列オブジェクトへの書き込みを行うコマンドを挿入します。

int org.jocl.CL.clEnqueueWriteImage(
    cl_command_queue command_queue, //(1)
    cl_mem image, //(2)
    boolean blocking_write, //(3)
    long[] origin, //(4)
    long[] region, //(5)
    long input_row_pitch, //(6)
    long input_slice_pitch, //(7)
    Pointer ptr, //(8)
    int num_events_in_wait_list, //(9)
    cl_event[] event_wait_list, //(10)
    cl_event event) //(11)

(1)

書き込みコマンドを挿入するコマンドキューを指定。command_queueとimageは同じOpenCLコンテキスト上で生成される必要がある。

(2)

有効なイメージオブジェクトまたはイメージ配列オブジェクトを指定します。

(3)

書き込み操作をブロッキング、またはノンブロッキングで行うのかを指定。blocking_writeにCL_TRUEを指定すると、OpenCL実装はptrが参照するデータを複製しコマンドキューに書き込み操作を挿入。clEnqueueWriteImageが戻った後は、アプリケーションはptrが指すメモリを再利用できる。

(4)

書き込みを行うイメージ内での (x, y, z) オフセットをピクセルで指定。image が2Dイメージオブジェクトであるとき、origin[2] で指定する z 値は0でなければなりません。

(5)

1D、2D、3D矩形領域の(width, height, depth) をピクセルで定義。 2D矩形領域の(width, height)をピクセルで定義し、2Dイメージ配列のイメージ個数の定義。1D矩形領域の(width)をピクセルで定義し、1Dイメージ配列のイメージ個数を定義。

(6)

各行が使用する長さをバイトで指定。この値は、画素のバイトサイズ*width以上となる必要がある。row_pitchに0を設定すると、画素のバイトサイズ*widthに基づいて適切な長さが計算される。

(7)

読み込み、または書き込まれる3Dイメージ内の3D領域の各2Dスライス、または1Dまたは2Dイメージ配列の各イメージが使用する長さを指定(バイトで表す)。 イメージが1Dまたは2Dの場合は、この引数は0となります。

(8)

書き込むイメージデータの保存先となるホストメモリバッファへのポインタを指定。

(9)

event_wait_listで指定したイベントオブジェクトの数を指定。

(10)

このコマンドが実行される前に完了されているイベントを指定

(11)

書き込みコマンドを識別するイベントオブジェクトが戻され、コマンド完了の確認やコマンド完了の待機に使える。

clEnqueueWriteImageとclEnqueueReadImageはバッファオブジェクトの読み書き関数の時と同じように、引数はホストポインタを除き同じものを使います。

実装例

イメージオブジェクトの読み込みと書き込みのソースコードとなります。

ImageReadWriteTest.java. 

package com.book.jocl.image;

import static org.jocl.CL.*;

import org.jocl.CL;
import org.jocl.Pointer;
import org.jocl.Sizeof;
import org.jocl.cl_command_queue;
import org.jocl.cl_context;
import org.jocl.cl_context_properties;
import org.jocl.cl_device_id;
import org.jocl.cl_image_desc;
import org.jocl.cl_image_format;
import org.jocl.cl_kernel;
import org.jocl.cl_mem;
import org.jocl.cl_platform_id;
import org.jocl.cl_program;

import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.awt.*;
import javax.swing.*;
import javax.imageio.*;
import java.io.*;
import java.net.URL;
import java.nio.file.Paths;
import java.util.Scanner;


public class ImageReadWriteTest {
        private static final String IMAGE_PATH = "SAMPLE.png";
        private static final String KERNEL_PATH = "image.cl";
        private static final String KERNEL_FUNC = "image_filter";

    private static cl_context context;
    private static cl_command_queue queue;
    private static cl_program program;
    private static cl_kernel kernel;

    private static ImageIcon img;
    private static int width;
    private static int height;

        public static void main(String[] args) throws Exception {

                CL.setExceptionsEnabled(true);

                cl_platform_id platform[] = new cl_platform_id[1];
                clGetPlatformIDs(1,  platform, null);
                cl_device_id device[] = new cl_device_id[1];
                int num_devices[] = new int[1];
                clGetDeviceIDs(platform[0], CL_DEVICE_TYPE_GPU, 1, device, num_devices);
                cl_context_properties props = new cl_context_properties();
                props.addProperty(CL_CONTEXT_PLATFORM, platform[0]);
                context = clCreateContext(props, 1, device, null, null, null);
                queue = clCreateCommandQueue(context, device[0], 0, null);

                StringBuffer sb = new StringBuffer();
                URL resource = ImageReadWriteTest.class.getResource(KERNEL_PATH);
                String path = Paths.get(resource.toURI()).toFile().getAbsolutePath();
                System.out.println(path);
                Scanner sc = new Scanner(new File(path));
                while(sc.hasNext()) {
                        sb.append(sc.nextLine() + "\n");
                }
        program = clCreateProgramWithSource(context,
                1, new String[]{sb.toString()}, null, null);

        clBuildProgram(program, 0, null, null, null, null);

        kernel = clCreateKernel(program, KERNEL_FUNC, null);

                URL imgResource = ImageReadWriteTest.class.getResource(IMAGE_PATH);

                String imgPath = Paths.get(imgResource.toURI()).toFile().getAbsolutePath();
                System.out.println(imgPath);
        img = new ImageIcon(imgResource);

        width = img.getIconWidth();
        height = img.getIconHeight();

        BufferedImage bimg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics g = bimg.createGraphics();
        img.paintIcon(null, g, 0,0);
        g.dispose();
        DataBufferInt dbb = (DataBufferInt)bimg.getRaster().getDataBuffer();
            int[] intArray = dbb.getData();
            System.out.println(intArray.length);

        cl_image_format format = new cl_image_format();
        format.image_channel_data_type = CL_UNORM_INT8;
        format.image_channel_order = CL_RGBA;
        cl_image_desc desc = new cl_image_desc();
        desc.image_height = img.getIconHeight();
        desc.image_width = img.getIconWidth();
        desc.num_mip_levels = 0;
        desc.num_samples = 0;
        desc.image_type = CL_MEM_OBJECT_IMAGE2D;

        cl_mem img_mem = clCreateImage(context,
                        CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR,
                        format,
                        desc,
                        null,
                        null);

        clEnqueueWriteImage(queue,
            img_mem,
            CL_TRUE,
            new long[]{0,0,0},
            new long[]{width,height,1},0,0,
            Pointer.to(intArray),
            0, null, null); //(1)

        int[] dstArray = new int[90000];

        clEnqueueReadImage(queue,
            img_mem,
            CL_TRUE,
            new long[]{0,0,0},
            new long[]{300,300,1},0, 0,
            Pointer.to(dstArray),
            0, null, null); //(2)

                BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
                image.setRGB(0, 0, width, height, dstArray, 0, width);

                System.out.println(width+"-"+height);

                resource = ImageReadWriteTest.class.getResource("./");
                path = Paths.get(resource.toURI()).toFile().getAbsolutePath();
                System.out.println(path+"/writeimage.png");
        ImageIO.write(image, "png", new File(path+"/writeimage.png"));

        clReleaseMemObject(img_mem);
                clReleaseDevice(device[0]);
                clReleaseContext(context);
                clReleaseCommandQueue(queue);
                clReleaseProgram(program);

        }

}

(1)

intArrayをimg_memバッファに書き込みます。

(2)

img_memバッファを読み込み、内容をdstArrayに書き込みます。

9.8.2. clEnqueueCopyImage

clEnqueueCopyImage関数はイメージオブジェクトの複製を行うコマンドを挿入します。src_imageおよびdst_imageには1D、2D、3Dイメージオブジェクト、1D/2Dイメージ配列オブジェクトを指定でき以下の操作が可能です。

  • 1Dイメージオブジェクトから1Dイメージオブジェクトへの複製
  • 1Dイメージオブジェクトから2Dイメージオブジェクトの走査線への複製(逆もまた同様)
  • 1Dイメージオブジェクトから3Dイメージオブジェクトの2Dスライスの走査線への複製(逆もまた同様)
  • 1Dイメージオブジェクトから1Dまたは2Dイメージ配列オブジェクトの特定イメージインデックスの走査線への複製(逆もまた同様)
  • 2Dイメージオブジェクトから2Dイメージオブジェクトへの複製
  • 2Dイメージオブジェクトから3Dイメージオブジェクトの2Dスライスへの複製(逆もまた同様)
  • 2Dイメージオブジェクトから2Dイメージ配列オブジェクトの特定イメージインデックスへの複製(逆もまた同様)
  • 1Dイメージ配列オブジェクトのイメージから1Dイメージ配列オブジェクトへの複製。
  • 2Dイメージ配列オブジェクトのイメージから2Dイメージ配列オブジェクトへの複製。
  • 3Dイメージオブジェクトから3Dイメージオブジェクトへの複製

注記

詳しくは「表:clEnqueueCopyImage」(表B.45「表:clEnqueueCopyImage」)を参照ください。

int org.jocl.CL.clEnqueueCopyImage(
    cl_command_queue command_queue, //(1)
    cl_mem src_image, //(2)
    cl_mem dst_image, //(3)
    long[] src_origin, //(4)
    long[] dst_origin, //(5)
    long[] region, //(6)
    int num_events_in_wait_list, //(7)
    cl_event[] event_wait_list, //(8)
    cl_event event) //(9)

(1)

複製コマンドを挿入するコマンドキューを指定。command_queue、src_image、dst_imageと関連付けられたOpenCLコンテキストは同じとなる必要がある。

(2)

複製元となる有効なイメージオブジェクトを指定します。

(3)

複製先となる有効なイメージオブジェクトを指定します。

(4)

1D, 2D, 3Dイメージ内での (x, y, z) オフセットをピクセルで指定。2Dイメージ配列の(x, y)オフセットとイメージインデックスを指定。1Dイメージ配列の(x)オフセットとイメージインデックスを指定。

(5)

1D, 2D, 3Dイメージ内での (x, y, z) オフセットをピクセルで指定。2Dイメージ配列の(x, y)オフセットとイメージインデックスを指定。1Dイメージ配列の(x)オフセットとイメージインデックスを指定。

(6)

1D、2D、3D矩形領域の(width, height, depth) をピクセルで定義。2D矩形領域の(width, height)をピクセルで定義し、2Dイメージ配列のイメージ個数の定義。1D矩形領域の(width)をピクセルで定義し、1Dイメージ配列のイメージ個数を定義。

(7)

event_wait_listで指定したイベントオブジェクトの数を指定。

(8)

このコマンドが実行される前に完了されているイベントを指定。event_wait_listがNULLの場合、このコマンドはどのイベントの完了待機もしない。

(9)

複製コマンドを識別するイベントオブジェクトが戻され、コマンド完了の確認やコマンド完了の待機に使える。

9.8.3. clEnqueueFillImage

clEnqueueFillImage関数はイメージオブジェクトを指定した色彩に塗りつぶすコマンドをキューに挿入します。clEnguqueFillImageはカーネル/ホストによるメモリオブジェクトへの読み込み・書き込みについての使用情報や、イメージが生成された際に指定したcl_mem_flagsを無視します。

注記

詳しくは「表:clEnqueueFillImage」(表B.46「表:clEnqueueFillImage」)を参照ください。

int org.jocl.CL.clEnqueueFillImage(
    cl_command_queue command_queue, //(1)
    cl_mem image, //(2)
    Pointer fill_color, //(3)
    long[] origin, //(4)
    long[] region, //(5)
    int num_events_in_wait_list, //(6)
    cl_event[] event_wait_list, //(7)
    cl_event event) //(8)

(1)

fillコマンドが挿入されるcommand-queueを指定。command-queueとimageが関連するOpenCLコンテキストは同じものとなる必要がある。

(2)

有効なイメージオブジェクトを指定。

(3)

フィルカラー(塗りつぶす色)を指定。イメージチャネルデータ型が非正規符号付き・符号無し整数でない場合、フィルカラーは4つの要素で構成するRGBA浮動小数点色彩値となる。

(4)

1D、2D、3Dイメージ内の(x,y,z)オフセットをピクセルで指定。2Dイメージ配列内の(x,y)オフセットとイメージインデックスを指定。1Dイメージ配列内の(x)オフセットとイメージインデックスを指定。

(5)

1D、2D、3D矩形領域の(width, height, depth) をピクセルで定義。2D矩形領域の(width, height)をピクセルで定義し、2Dイメージ配列のイメージ個数の定義。1D矩形領域の(width)をピクセルで定義し、1Dイメージ配列のイメージ個数を定義。

(6)

event_wait_listで指定したイベントオブジェクトの数を指定。

(7)

このコマンドが実行される前に完了されているイベントを指定。event_wait_listがNULLの場合、このコマンドはどのイベントの完了待機もしない。

(8)

このコマンドを識別するイベントオブジェクトが戻され、コマンド完了の確認やコマンド完了の待機に使える。eventがNULLの場合、アプリケーションはコマンドの状況確認やコマンド完了待ちができなくなる。

実装例としては以下のようにオフセット、幅、高さ、色彩を引数に設定します。

origin[0] = 0;
origin[1] = 0;
origin[2] = 0;
region[0] = width;
region[1] = height;
region[2] = 1;

int color[4] = {0,0,80,150};
err = clEnqueueFillImage(queue,
        input_image,
        color,
        origin,
        region,
        0,
        NULL,
        NULL);
if(err < 0) {
  perror("Couldn't fill the input image object");
  exit(1);
};

9.8.4. clEnqueueCopyImageToBuffer

clEnqueueCopyImageToBuffer関数はイメージオブジェクトからバッファオブジェクトへの複製を行うコマンドを挿入。

注記

詳細は「表:clEnqueueCopyImageToBuffer」(表B.47「表:clEnqueueCopyImageToBuffer」)を参照ください。

int org.jocl.CL.clEnqueueCopyImageToBuffer(
    cl_command_queue command_queue, //(1)
    cl_mem src_image, //(2)
    cl_mem dst_buffer, //(3)
    long[] src_origin, //(4)
    long[] region, //(5)
    long dst_offset, //(6)
    int num_events_in_wait_list, //(7)
    cl_event[] event_wait_list, //(8)
    cl_event event) //(9)

(1)

複製コマンドを挿入するコマンドキューを指定。command_queue、src_image、dst_buffer と関連付けられたOpenCLコンテキストは同じとなる必要がある。

(2)

複製元となる有効なイメージオブジェクトを指定します。

(3)

複製先となる有効なバッファオブジェクトを指定します。

(4)

1D, 2D, 3Dイメージ内での (x, y, z) オフセットをピクセルで指定。 2Dイメージ配列の(x, y)オフセットとイメージインデックスを指定。 1Dイメージ配列の(x)オフセットとイメージインデックスを指定。

(5)

1D、2D、3D矩形領域の(width, height, depth) をピクセルで定義。2D矩形領域の(width, height)をピクセルで定義し、2Dイメージ配列のイメージ個数の定義。1D矩形領域の(width)をピクセルで定義し、1Dイメージ配列のイメージ個数を定義。

(6)

dst_bufferへのデータの複製を行なう際に、書き込み開始位置をどれだけずらすかを指定。src_imageが3Dイメージオブジェクトの場合、複製領域のバイトサイズ(dst_cb) はwidth*height*depth*(画素あたりのバイトサイズ)で求められる。src_imageが2Dイメージオブジェクトの場合、複製領域のバイトサイズ(dst_cb) はwidth*height*(画素あたりのバイトサイズ)で求められる。src_imageが2Dイメージ配列オブジェクトの場合、複製領域のバイトサイズ(dst_cb) はwidth*height*配列サイズ*(画素あたりのバイトサイズ)で求められる。

(7)

event_wait_list で指定したイベントオブジェクトの数を指定します。

(8)

このコマンドが実行される前に完了されているイベントを指定。event_wait_listがNULLの場合、このコマンドはどのイベントの完了待機もしない。

(9)

複製コマンドを識別するイベントオブジェクトが戻され、コマンド完了の確認やコマンド完了の待機に使える。eventがNULLの場合、アプリケーションはコマンドの状況確認やコマンド完了待ちができなくなる。

9.8.5. clEnqueueCopyBufferToImage

clEnqueueCopyBufferToImage関数はバッファオブジェクトからイメージオブジェクトへの複製を行うコマンドを挿入します。

注記

詳しくは「表:clEnqueueCopyBufferToImage」(表B.48「表:clEnqueueCopyBufferToImage」)を参照ください。

int org.jocl.CL.clEnqueueCopyBufferToImage(
    cl_command_queue command_queue, //(1)
    cl_mem src_buffer, //(2)
    cl_mem dst_image, //(3)
    long src_offset, //(4)
    long[] dst_origin, //(5)
    long[] region, //(6)
    int num_events_in_wait_list, //(7)
    cl_event[] event_wait_list, //(8)
    cl_event event) //(9)

(1)

複製コマンドを挿入するコマンドキューを指定します。command_queue、src_buffer、dst_imageと関連付けられたOpenCLコンテキストは同じとなる必要がある。

(2)

複製元となる有効なバッファオブジェクトを指定。

(3)

複製先となる有効なイメージオブジェクトを指定。

(4)

src_bufferから複製を行う際に、読み込み開始位置をどれだけずらすかを指定。

(5)

1D、2D、3Dイメージ内の(x,y,z)オフセットをピクセルで指定。2Dイメージ配列内の(x,y)オフセットとイメージインデックスを指定。1Dイメージ配列内の(x)オフセットとイメージインデックスを指定。

(6)

1D、2D、3D矩形領域の(width, height, depth) をピクセルで定義。2D矩形領域の(width, height)をピクセルで定義し、2Dイメージ配列のイメージ個数の定義。1D矩形領域の(width)をピクセルで定義し、1Dイメージ配列のイメージ個数を定義。

(7)

event_wait_listで指定したイベントオブジェクトの数を指定します。

(8)

このコマンドが実行される前に完了されているイベントを指定。event_wait_listがNULLの場合、このコマンドはどのイベントの完了待機もしない。

(9)

複製コマンドを識別するイベントオブジェクトが戻され、コマンド完了の確認やコマンド完了の待機に使える。eventがNULLの場合、アプリケーションはコマンドの状況確認やコマンド完了待ちができなくなる。

Copyright 2018-2019, by Masaki Komatsu