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}