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 com.nativelibs4java.opencl.ImageIOUtils.ImageInfo;
052import static com.nativelibs4java.opencl.library.IOpenCLLibrary.CL_IMAGE_HEIGHT;
053import static com.nativelibs4java.opencl.library.IOpenCLLibrary.CL_IMAGE_ROW_PITCH;
054import static com.nativelibs4java.opencl.library.IOpenCLLibrary.CL_IMAGE_WIDTH;
055
056import java.awt.Image;
057import java.awt.image.BufferedImage;
058import java.nio.Buffer;
059import java.nio.ByteBuffer;
060import java.nio.IntBuffer;
061
062import org.bridj.Pointer;
063import org.bridj.SizeT;
064import static org.bridj.Pointer.*;
065
066import com.nativelibs4java.opencl.library.IOpenCLLibrary.cl_mem;
067import com.nativelibs4java.util.Pair;
068
069/**
070 * OpenCL 2D Image Memory Object<br>
071 * see {@link CLContext#createImage2D(com.nativelibs4java.opencl.CLMem.Usage, java.awt.Image, boolean) }
072 * see {@link CLContext#createImage2D(com.nativelibs4java.opencl.CLMem.Usage, com.nativelibs4java.opencl.CLImageFormat, long, long) }
073 * see {@link CLContext#createImage2D(com.nativelibs4java.opencl.CLMem.Usage, com.nativelibs4java.opencl.CLImageFormat, long, long, long) }
074 * see {@link CLContext#createImage2D(com.nativelibs4java.opencl.CLMem.Usage, com.nativelibs4java.opencl.CLImageFormat, long, long, long, java.nio.Buffer, boolean) }
075 * see {@link CLContext#createImage2DFromGLRenderBuffer(com.nativelibs4java.opencl.CLMem.Usage, int) }
076 * see {@link CLContext#createImage2DFromGLTexture2D(com.nativelibs4java.opencl.CLMem.Usage, com.nativelibs4java.opencl.CLContext.GLTextureTarget, int, int) } 
077 * @author Olivier Chafik
078 */
079public class CLImage2D extends CLImage {
080        CLImage2D(CLContext context, long entityPeer, CLImageFormat format) {
081        super(context, entityPeer, format);
082        }
083
084        /**
085         * Return size in bytes of a row of elements of the image object given by image.
086         */
087        @InfoName("CL_IMAGE_ROW_PITCH")
088        public long getRowPitch() {
089                return infos.getIntOrLong(getEntity(), CL_IMAGE_ROW_PITCH);
090        }
091
092        /**
093         * Return width of the image in pixels
094         */
095        @InfoName("CL_IMAGE_WIDTH")
096        public long getWidth() {
097                return infos.getIntOrLong(getEntity(), CL_IMAGE_WIDTH);
098        }
099
100        /**
101         * Return height of the image in pixels
102         */
103        @InfoName("CL_IMAGE_HEIGHT")
104        public long getHeight() {
105                return infos.getIntOrLong(getEntity(), CL_IMAGE_HEIGHT);
106        }
107
108        @Override
109        protected long[] getDimensions() {
110                return new long[] { getWidth(), getHeight() };
111        }
112
113    @Override
114    protected Pointer<SizeT> writeOrigin(long[] origin, ReusablePointer out) {
115        assert(origin.length == 2);
116        return out.pointerToSizeTs(origin[0], origin[1], 0);
117    }
118    
119    @Override
120    protected Pointer<SizeT> writeRegion(long[] region, ReusablePointer out) {
121        assert(region.length == 2);
122        return out.pointerToSizeTs(region[0], region[1], 1);
123    }
124
125        /**
126         * @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.  
127     * @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}.
128         */
129        public CLEvent read(CLQueue queue, long minX, long minY, long width, long height, long rowPitch, Buffer out, boolean blocking, CLEvent... eventsToWaitFor) {
130                Pointer<?> ptrOut = pointerToBuffer(out);
131                CLEvent evt = read(queue, minX, minY, width, height, rowPitch, ptrOut, blocking, eventsToWaitFor);
132                ptrOut.updateBuffer(out); // in case the buffer wasn't direct !
133                return evt;
134        }
135        /**
136         * @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.  
137     * @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}.
138         */
139        public CLEvent read(CLQueue queue, long minX, long minY, long width, long height, long rowPitch, Pointer<?> out, boolean blocking, CLEvent... eventsToWaitFor) {
140                return read(queue, pointerToSizeTs(minX, minY, 0), pointerToSizeTs(width, height, 1), rowPitch, 0, out, blocking, eventsToWaitFor);
141        }
142        /**
143         * @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.  
144     * @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}.
145         */
146        public CLEvent write(CLQueue queue, long minX, long minY, long width, long height, long rowPitch, Buffer in, boolean blocking, CLEvent... eventsToWaitFor) {
147                return write(queue, minX, minY, width, height, rowPitch, pointerToBuffer(in), blocking, eventsToWaitFor);
148        }
149        /**
150         * @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.  
151     * @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}.
152         */
153        public CLEvent write(CLQueue queue, long minX, long minY, long width, long height, long rowPitch, Pointer<?> in, boolean blocking, CLEvent... eventsToWaitFor) {
154                return write(queue, pointerToSizeTs(minX, minY, 0), pointerToSizeTs(width, height, 1), rowPitch, 0, in, blocking, eventsToWaitFor);
155        }
156
157        /**
158         * @param eventsToWaitFor Events that need to complete before this particular command can be executed.
159     */
160        public BufferedImage read(CLQueue queue, CLEvent... eventsToWaitFor) {
161        ImageInfo info = ImageIOUtils.getBufferedImageInfo(getFormat());
162        int imageType = info == null ? 0 : info.bufferedImageType;
163        if (imageType == 0)
164            throw new UnsupportedOperationException("Cannot convert image of format " + getFormat() + " to a BufferedImage.");
165            //imageType = BufferedImage.TYPE_INT_ARGB;
166        
167                BufferedImage im = new BufferedImage((int)getWidth(), (int)getHeight(), imageType);
168                read(queue, im, false, eventsToWaitFor);
169                return im;
170        }
171        /**
172         * @param eventsToWaitFor Events that need to complete before this particular command can be executed.  
173     */
174        public void read(CLQueue queue, BufferedImage imageOut, boolean allowDeoptimizingDirectWrite, CLEvent... eventsToWaitFor) {
175                //if (!getFormat().isIntBased())
176                //      throw new IllegalArgumentException("Image-read only supports int-based RGBA images");
177        ImageInfo info = ImageIOUtils.getBufferedImageInfo(getFormat());
178        int width = imageOut.getWidth(null), height = imageOut.getHeight(null);
179
180        Pointer<?> dataOut = allocateArray(info.bufferElementsClass, width * height * info.channelCount).order(getContext().getByteOrder());
181                //Buffer dataOut = info.createBuffer(width, height, true);
182                //IntBuffer dataOut = directInts(width * height, getContext().getByteOrder());
183                read(queue, 0, 0, width, height, 0, dataOut, true, eventsToWaitFor);
184        info.dataSetter.setData(imageOut, dataOut.getBuffer(), allowDeoptimizingDirectWrite);
185        }
186        /**
187         * @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.  
188     * @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}.
189         */
190        public CLEvent write(CLQueue queue, Image image, CLEvent... eventsToWaitFor) {
191                return write(queue, image, 0, 0, image.getWidth(null), image.getHeight(null), false, false, eventsToWaitFor);
192        }
193        /**
194         * @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.  
195     * @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}.
196         */
197        public CLEvent write(CLQueue queue, Image image, boolean allowDeoptimizingDirectRead, boolean blocking, CLEvent... eventsToWaitFor) {
198                return write(queue, image, 0, 0, image.getWidth(null), image.getHeight(null), allowDeoptimizingDirectRead, blocking, eventsToWaitFor);
199        }
200        /**
201         * @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.  
202     * @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}.
203         */
204        public CLEvent write(CLQueue queue, Image image, int destX, int destY, int width, int height, boolean allowDeoptimizingDirectRead, boolean blocking, CLEvent... eventsToWaitFor) {
205                //int imWidth = image.getWidth(null), height = image.getHeight(null);
206        ImageInfo info = ImageIOUtils.getBufferedImageInfo(getFormat());
207                return write(queue, 0, 0, width, height, width * info.pixelByteSize, info.dataGetter.getData(image, null, false, allowDeoptimizingDirectRead, getContext().getByteOrder()), blocking, eventsToWaitFor);
208        }
209        public void write(CLQueue queue, BufferedImage imageIn, boolean allowDeoptimizingDirectRead, CLEvent... eventsToWaitFor) {
210                //if (!getFormat().isIntBased())
211                //      throw new IllegalArgumentException("Image read only supports int-based RGBA images");
212
213                int width = imageIn.getWidth(null), height = imageIn.getHeight(null);
214                ImageInfo<BufferedImage> info = ImageIOUtils.getBufferedImageInfo(getFormat());
215                write(queue, 0, 0, width, height, 0, info.dataGetter.getData(imageIn, null, false, allowDeoptimizingDirectRead, getContext().getByteOrder()), true, eventsToWaitFor);
216        }
217        public void write(CLQueue queue, BufferedImage im) {
218                write(queue, im, false);
219        }
220
221    public ByteBuffer map(CLQueue queue, MapFlags flags, CLEvent... eventsToWaitFor) {
222        return map(queue, flags, pointerToSizeTs(0, 0), pointerToSizeTs(getWidth(), getHeight()), getWidth(), null, true, eventsToWaitFor).getFirst();
223    }
224        public ByteBuffer map(CLQueue queue, MapFlags flags, long offsetX, long offsetY, long lengthX, long lengthY, long rowPitch, CLEvent... eventsToWaitFor) {
225                return map(queue, flags, pointerToSizeTs(offsetX, offsetY), pointerToSizeTs(lengthX, lengthY), rowPitch, null, true, eventsToWaitFor).getFirst();
226    }
227        /**
228         * @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.  
229     * @return Pair with byte buffer and 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}.
230         */
231        public Pair<ByteBuffer, CLEvent> mapLater(CLQueue queue, MapFlags flags, boolean blocking, CLEvent... eventsToWaitFor) {
232                return map(queue, flags, pointerToSizeTs(0, 0), pointerToSizeTs(getWidth(), getHeight()), getWidth(), null, blocking, eventsToWaitFor);
233    }
234    /**
235         * @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.  
236     * @return Pair with byte buffer and 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}.
237         */
238        public Pair<ByteBuffer, CLEvent> mapLater(CLQueue queue, MapFlags flags, long offsetX, long offsetY, long lengthX, long lengthY, long rowPitch, boolean blocking, CLEvent... eventsToWaitFor) {
239                return map(queue, flags, pointerToSizeTs(offsetX, offsetY), pointerToSizeTs(lengthX, lengthY), rowPitch, null, blocking, eventsToWaitFor);
240    }
241}