001/*
002 * JavaCL - Java API and utilities for OpenCL
003 * http://javacl.googlecode.com/
004 *
005 * Copyright (c) 2009-2013, Olivier Chafik (http://ochafik.com/)
006 * All rights reserved.
007 *
008 * Redistribution and use in source and binary forms, with or without
009 * modification, are permitted provided that the following conditions are met:
010 * 
011 *     * Redistributions of source code must retain the above copyright
012 *       notice, this list of conditions and the following disclaimer.
013 *     * Redistributions in binary form must reproduce the above copyright
014 *       notice, this list of conditions and the following disclaimer in the
015 *       documentation and/or other materials provided with the distribution.
016 *     * Neither the name of Olivier Chafik nor the
017 *       names of its contributors may be used to endorse or promote products
018 *       derived from this software without specific prior written permission.
019 * 
020 * THIS SOFTWARE IS PROVIDED BY OLIVIER CHAFIK AND CONTRIBUTORS ``AS IS'' AND ANY
021 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
022 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
023 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
024 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
025 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
026 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
027 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
029 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
030 */
031        
032
033
034
035
036        
037
038        
039        
040
041
042
043        
044
045        
046        
047        
048
049        
050package com.nativelibs4java.opencl;
051import static com.nativelibs4java.opencl.CLException.error;
052import static com.nativelibs4java.opencl.JavaCL.CL;
053import static com.nativelibs4java.opencl.JavaCL.check;
054import static com.nativelibs4java.opencl.library.IOpenCLLibrary.CL_FALSE;
055import static com.nativelibs4java.opencl.library.IOpenCLLibrary.CL_IMAGE_ELEMENT_SIZE;
056import static com.nativelibs4java.opencl.library.IOpenCLLibrary.CL_IMAGE_FORMAT;
057import static com.nativelibs4java.opencl.library.IOpenCLLibrary.CL_TRUE;
058import static com.nativelibs4java.util.NIOUtils.directCopy;
059
060import java.nio.Buffer;
061import java.nio.ByteBuffer;
062import java.nio.ByteOrder;
063import java.nio.IntBuffer;
064
065import com.nativelibs4java.opencl.library.cl_image_format;
066import com.nativelibs4java.opencl.library.IOpenCLLibrary.cl_event;
067import com.nativelibs4java.opencl.library.IOpenCLLibrary.cl_mem;
068import com.nativelibs4java.util.NIOUtils;
069
070import com.nativelibs4java.util.Pair;
071import org.bridj.*;
072import static org.bridj.Pointer.*;
073
074
075/**
076 * OpenCL Image Memory Object.<br>
077 * An image object is used to store a two- or three- dimensional texture, frame-buffer or image<br>
078 * An image object is used to represent a buffer that can be used as a texture or a frame-buffer. The elements of an image object are selected from a list of predefined image formats.
079 * @author Oliveir Chafik
080 */
081public abstract class CLImage extends CLMem {
082
083        CLImageFormat format;
084        CLImage(CLContext context, long entityPeer, CLImageFormat format) {
085        super(context, -1, entityPeer);
086                this.format = format;
087        }
088
089        protected abstract long[] getDimensions();
090
091        /**
092         * Return image format descriptor specified when image is created with CLContext.create{Input|Output|InputOutput}{2D|3D}.
093         */
094        @InfoName("CL_IMAGE_FORMAT")
095        public CLImageFormat getFormat() {
096                if (format == null) {
097                        format = new CLImageFormat(new cl_image_format(infos.getMemory(getEntity(), CL_IMAGE_FORMAT)));
098                }
099                return format;
100        }
101
102        /**
103         * Return size of each element of the image memory object given by image. <br>
104         * An element is made up of n channels. The value of n is given in cl_image_format descriptor.
105         */
106        @InfoName("CL_IMAGE_ELEMENT_SIZE")
107        public long getElementSize() {
108                return infos.getIntOrLong(getEntity(), CL_IMAGE_ELEMENT_SIZE);
109        }
110
111        /**
112  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueReadImage.html">clEnqueueReadImage</a>.<br>
113     */
114    protected CLEvent read(CLQueue queue, Pointer<SizeT> origin, Pointer<SizeT> region, long rowPitch, long slicePitch, Buffer out, boolean blocking, CLEvent... eventsToWaitFor) {
115                return read(queue, origin, region, rowPitch, slicePitch, pointerToBuffer(out), blocking, eventsToWaitFor);
116        }
117        /**
118  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueReadImage.html">clEnqueueReadImage</a>.<br>
119     */
120    protected CLEvent read(CLQueue queue, Pointer<SizeT> origin, Pointer<SizeT> region, long rowPitch, long slicePitch, Pointer<?> out, boolean blocking, CLEvent... eventsToWaitFor) {
121                /*if (!out.isDirect()) {
122
123                }*/
124                                ReusablePointers ptrs = ReusablePointers.get();
125                int[] eventsInCount = ptrs.int1Array;
126        Pointer<cl_event> eventsIn = 
127                CLAbstractEntity.copyNonNullEntities(eventsToWaitFor, eventsInCount, ptrs.events_in);
128                Pointer<cl_event> eventOut = 
129                blocking || eventsToWaitFor == null || CLEvent.containsFireAndForget(eventsToWaitFor) 
130                ? null 
131                : ptrs.event_out;
132        error(CL.clEnqueueReadImage(
133                queue.getEntity(), 
134                getEntity(),
135                        blocking ? CL_TRUE : CL_FALSE,
136                        getPeer(origin),
137                        getPeer(region),
138                        rowPitch,
139                        slicePitch,
140                        getPeer(out),
141                          eventsInCount[0], getPeer(eventsIn) ,  getPeer(eventOut)              ));
142                 return  CLEvent.createEventFromPointer(queue, eventOut) ;      }
143
144        /**
145  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueWriteImage.html">clEnqueueWriteImage</a>.<br>
146     */
147    protected CLEvent write(CLQueue queue, Pointer<SizeT> origin, Pointer<SizeT> region, long rowPitch, long slicePitch, Buffer in, boolean blocking, CLEvent... eventsToWaitFor) {
148                return write(queue, origin, region, rowPitch, slicePitch, pointerToBuffer(in), blocking, eventsToWaitFor);
149        }
150        /**
151  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueWriteImage.html">clEnqueueWriteImage</a>.<br>
152     */
153    protected CLEvent write(CLQueue queue, Pointer<SizeT> origin, Pointer<SizeT> region, long rowPitch, long slicePitch, Pointer<?> in, boolean blocking, CLEvent... eventsToWaitFor) {
154                                ReusablePointers ptrs = ReusablePointers.get();
155                int[] eventsInCount = ptrs.int1Array;
156        Pointer<cl_event> eventsIn = 
157                CLAbstractEntity.copyNonNullEntities(eventsToWaitFor, eventsInCount, ptrs.events_in);
158                Pointer<cl_event> eventOut = 
159                blocking || eventsToWaitFor == null || CLEvent.containsFireAndForget(eventsToWaitFor) 
160                ? null 
161                : ptrs.event_out;
162        error(CL.clEnqueueWriteImage(
163                queue.getEntity(),
164                getEntity(),
165                        blocking ? CL_TRUE : CL_FALSE,
166                        getPeer(origin),
167                        getPeer(region),
168                        rowPitch,
169                        slicePitch,
170                        getPeer(in),
171                          eventsInCount[0], getPeer(eventsIn) ,  getPeer(eventOut)              ));
172                CLEvent evt =  CLEvent.createEventFromPointer(queue, eventOut) ;
173
174                if (!blocking) {
175                        final Pointer<?> toHold = in;
176                        evt.invokeUponCompletion(new Runnable() {
177                                public void run() {
178                                        // Make sure the GC held a reference to directData until the write was completed !
179                                        toHold.order();
180                                }
181                        });
182                }
183
184                return evt;
185        }
186
187    /**
188  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueFillImage.html">clEnqueueFillImage</a>.<br>
189     * @param queue
190     * @param queue Queue on which to enqueue this fill buffer command.
191     * @param color Color components to fill the buffer with.
192         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
193     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
194     */
195    public CLEvent fillImage(CLQueue queue, Object color, CLEvent... eventsToWaitFor) {
196        long[] region = getDimensions();
197        long[] origin = new long[region.length];
198        return fillImage(queue, color, origin, region, eventsToWaitFor);
199    }
200
201    /**
202  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueFillImage.html">clEnqueueFillImage</a>.<br>
203     * @param queue
204     * @param queue Queue on which to enqueue this fill buffer command.
205     * @param color Color components to fill the buffer with.
206     * @param origin Origin point.
207     * @param region Size of the region to fill.
208         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
209     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
210     */
211    public CLEvent fillImage(CLQueue queue, Object color, long[] origin, long[] region, CLEvent... eventsToWaitFor) {
212        context.getPlatform().requireMinVersionValue("clEnqueueFillImage", 1.2);
213                Pointer<?> pColor;
214                if (color instanceof int[]) {
215                        pColor = pointerToInts((int[]) color);
216                } else if (color instanceof float[]) {
217                        pColor = pointerToFloats((float[]) color);
218                } else {
219                        throw new IllegalArgumentException("Color should be an int[] or a float[] with 4 elements.");
220                }
221                check(pColor.getValidElements() == 4, "Color should have 4 elements.");
222
223                                ReusablePointers ptrs = ReusablePointers.get();
224                int[] eventsInCount = ptrs.int1Array;
225        Pointer<cl_event> eventsIn = 
226                CLAbstractEntity.copyNonNullEntities(eventsToWaitFor, eventsInCount, ptrs.events_in);
227                Pointer<cl_event> eventOut = 
228                eventsToWaitFor == null || CLEvent.containsFireAndForget(eventsToWaitFor) 
229                ? null 
230                : ptrs.event_out;
231                error(CL.clEnqueueFillImage(
232                        queue.getEntity(),
233                        getEntity(),
234                        getPeer(pColor),
235                        getPeer(writeOrigin(origin, ptrs.sizeT3_1)),
236                        getPeer(writeRegion(region, ptrs.sizeT3_2)),
237                          eventsInCount[0], getPeer(eventsIn) ,  getPeer(eventOut)              ));
238         return  CLEvent.createEventFromPointer(queue, eventOut) ;     }
239
240        // clEnqueueFillImage ( cl_command_queue command_queue,
241 //     cl_mem image,
242 //     const void *fill_color,
243 //     const size_t *origin,
244 //     const size_t *region,
245 //     cl_uint num_events_in_wait_list,
246 //     const cl_event *event_wait_list,
247 //     cl_event *event)
248
249    protected Pair<ByteBuffer, CLEvent> map(CLQueue queue, MapFlags flags,
250            Pointer<SizeT> offset3, Pointer<SizeT> length3,
251            Long imageRowPitch,
252            Long imageSlicePitch,
253            boolean blocking, CLEvent... eventsToWaitFor)
254    {
255        if (flags == MapFlags.WriteInvalidateRegion) {
256            context.getPlatform().requireMinVersionValue("CL_MAP_WRITE_INVALIDATE_REGION", 1.2);
257        }
258                                ReusablePointers ptrs = ReusablePointers.get();
259                int[] eventsInCount = ptrs.int1Array;
260        Pointer<cl_event> eventsIn = 
261                CLAbstractEntity.copyNonNullEntities(eventsToWaitFor, eventsInCount, ptrs.events_in);
262                Pointer<cl_event> eventOut = 
263                blocking || eventsToWaitFor == null || CLEvent.containsFireAndForget(eventsToWaitFor) 
264                ? null 
265                : ptrs.event_out;
266                        Pointer<Integer> pErr = ptrs.pErr;
267        long mappedPeer = CL.clEnqueueMapImage(
268            queue.getEntity(), 
269            getEntity(), 
270            blocking ? CL_TRUE : CL_FALSE,
271            flags.value(),
272                        getPeer(offset3),
273            getPeer(length3),
274            imageRowPitch == null ? 0 : getPeer(ptrs.sizeT3_1.pointerToSizeTs((long)imageRowPitch)),
275            imageSlicePitch == null ? 0 : getPeer(ptrs.sizeT3_2.pointerToSizeTs((long)imageSlicePitch)),
276                          eventsInCount[0], getPeer(eventsIn) ,  getPeer(eventOut)  ,
277                        getPeer(pErr)
278                );
279                        error(pErr.getInt());
280        return new Pair<ByteBuffer, CLEvent>(
281                        pointerToAddress(mappedPeer).getByteBuffer(getByteCount()),
282                         CLEvent.createEventFromPointer(queue, eventOut)                );
283    }
284
285    /**
286  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueUnmapMemObject.html">clEnqueueUnmapMemObject</a>.<br>
287     * see {@link CLImage2D#map(com.nativelibs4java.opencl.CLQueue, com.nativelibs4java.opencl.CLMem.MapFlags, com.nativelibs4java.opencl.CLEvent[]) }
288     * see {@link CLImage3D#map(com.nativelibs4java.opencl.CLQueue, com.nativelibs4java.opencl.CLMem.MapFlags, com.nativelibs4java.opencl.CLEvent[]) }
289     * @param queue
290     * @param buffer
291         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
292     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
293     */
294    public CLEvent unmap(CLQueue queue, ByteBuffer buffer, CLEvent... eventsToWaitFor) {
295                        ReusablePointers ptrs = ReusablePointers.get();
296                int[] eventsInCount = ptrs.int1Array;
297        Pointer<cl_event> eventsIn = 
298                CLAbstractEntity.copyNonNullEntities(eventsToWaitFor, eventsInCount, ptrs.events_in);
299                Pointer<cl_event> eventOut = 
300                eventsToWaitFor == null || CLEvent.containsFireAndForget(eventsToWaitFor) 
301                ? null 
302                : ptrs.event_out;
303        Pointer<?> pBuffer = pointerToBuffer(buffer);
304        error(CL.clEnqueueUnmapMemObject(queue.getEntity(), getEntity(), getPeer(pBuffer),   eventsInCount[0], getPeer(eventsIn) ,  getPeer(eventOut)  ));
305                 return  CLEvent.createEventFromPointer(queue, eventOut) ;     }
306
307    protected abstract Pointer<SizeT> writeOrigin(long[] origin, ReusablePointer out);
308    protected abstract Pointer<SizeT> writeRegion(long[] region, ReusablePointer out);
309
310    /**
311  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueCopyImage.html">clEnqueueCopyImage</a>.<br>
312     * @param queue
313         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
314     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
315     */
316    public CLEvent copyTo(CLQueue queue, CLImage destination, CLEvent... eventsToWaitFor) {
317        long[] region = getDimensions();
318        long[] origin = new long[region.length];
319        return copyTo(queue, destination, origin, origin, region, eventsToWaitFor);
320    }
321
322    /**
323  * Calls <a href="http://www.khronos.org/registry/cl/sdk/1.2/docs/man/xhtml/clEnqueueCopyImage.html">clEnqueueCopyImage</a>.<br>
324     * @param queue
325         * @param eventsToWaitFor Events that need to complete before this particular command can be executed. Special value {@link CLEvent#FIRE_AND_FORGET} can be used to avoid returning a CLEvent.  
326     * @return Event object that identifies this command and can be used to query or queue a wait for the command to complete, or null if eventsToWaitFor contains {@link CLEvent#FIRE_AND_FORGET}.
327     */
328    public CLEvent copyTo(CLQueue queue, CLImage destination, long[] sourceOrigin, long[] destinationOrigin, long[] region, CLEvent... eventsToWaitFor) {
329                        ReusablePointers ptrs = ReusablePointers.get();
330                int[] eventsInCount = ptrs.int1Array;
331        Pointer<cl_event> eventsIn = 
332                CLAbstractEntity.copyNonNullEntities(eventsToWaitFor, eventsInCount, ptrs.events_in);
333                Pointer<cl_event> eventOut = 
334                eventsToWaitFor == null || CLEvent.containsFireAndForget(eventsToWaitFor) 
335                ? null 
336                : ptrs.event_out;
337        error(CL.clEnqueueCopyImage(
338            queue.getEntity(),
339            getEntity(),
340            destination.getEntity(),
341            getPeer(writeOrigin(sourceOrigin, ptrs.sizeT3_1)),
342            getPeer(writeOrigin(destinationOrigin, ptrs.sizeT3_2)),
343            getPeer(writeRegion(region, ptrs.sizeT3_3)),
344              eventsInCount[0], getPeer(eventsIn) ,  getPeer(eventOut)  ));
345                 return  CLEvent.createEventFromPointer(queue, eventOut) ;     }
346}