1 /*
2 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 #ifndef HEADLESS
27
28 #include <jni.h>
29 #include <jlong.h>
30
31 #include "SurfaceData.h"
32 #include "OGLBlitLoops.h"
33 #include "OGLRenderQueue.h"
34 #include "OGLSurfaceData.h"
35 #include "GraphicsPrimitiveMgr.h"
36
37 extern OGLPixelFormat PixelFormats[];
38
39 /**
40 * Inner loop used for copying a source OpenGL "Surface" (window, pbuffer,
41 * etc.) to a destination OpenGL "Surface". Note that the same surface can
42 * be used as both the source and destination, as is the case in a copyArea()
43 * operation. This method is invoked from OGLBlitLoops_IsoBlit() as well as
44 * OGLBlitLoops_CopyArea().
45 *
46 * The standard glCopyPixels() mechanism is used to copy the source region
47 * into the destination region. If the regions have different dimensions,
48 * the source will be scaled into the destination as appropriate (only
49 * nearest neighbor filtering will be applied for simple scale operations).
50 */
51 static void
52 OGLBlitSurfaceToSurface(OGLContext *oglc, OGLSDOps *srcOps, OGLSDOps *dstOps,
53 jint sx1, jint sy1, jint sx2, jint sy2,
54 jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
55 {
56 GLfloat scalex, scaley;
318 GLvoid *pSrc = PtrCoord(srcInfo->rasBase,
319 sx, srcInfo->pixelStride,
320 sy, srcInfo->scanStride);
321
322 while (tmph > 0) {
323 j2d_glTexSubImage2D(GL_TEXTURE_2D, 0,
324 0, sh - tmph, sw, 1,
325 pf->format, pf->type,
326 pSrc);
327 pSrc = PtrAddBytes(pSrc, srcInfo->scanStride);
328 tmph--;
329 }
330 } else {
331 j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, sx);
332 j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, sy);
333
334 j2d_glTexSubImage2D(GL_TEXTURE_2D, 0,
335 0, 0, sw, sh,
336 pf->format, pf->type,
337 srcInfo->rasBase);
338 }
339
340 // the texture image is "right side up", so we align the
341 // upper-left texture corner with the upper-left quad corner
342 j2d_glBegin(GL_QUADS);
343 j2d_glTexCoord2d(tx1, ty1); j2d_glVertex2d(dx, dy);
344 j2d_glTexCoord2d(tx2, ty1); j2d_glVertex2d(dx + dw, dy);
345 j2d_glTexCoord2d(tx2, ty2); j2d_glVertex2d(dx + dw, dy + dh);
346 j2d_glTexCoord2d(tx1, ty2); j2d_glVertex2d(dx, dy + dh);
347 j2d_glEnd();
348 } else {
349 // this accounts for lower-left origin of the source region
350 jint newsx = srcOps->xOffset + sx;
351 jint newsy = srcOps->yOffset + srcOps->height - (sy + sh);
352 j2d_glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
353 0, 0, newsx, newsy, sw, sh);
354
355 // the texture image is "upside down" after the last step, so
356 // we align the bottom-left texture corner with the upper-left
357 // quad corner (and vice versa) to effectively flip the
680 sx1, sy1, sx2, sy2,
681 dx1, dy1, dx2, dy2);
682 } else {
683 OGLBlitSwToSurface(oglc, &srcInfo, &pf,
684 sx1, sy1, sx2, sy2,
685 dx1, dy1, dx2, dy2);
686 }
687 }
688
689 j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
690 j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
691 j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
692 j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
693 }
694 SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
695 }
696 SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
697 }
698
699 /**
700 * Specialized blit method for copying a native OpenGL "Surface" (pbuffer,
701 * window, etc.) to a system memory ("Sw") surface.
702 */
703 void
704 OGLBlitLoops_SurfaceToSwBlit(JNIEnv *env, OGLContext *oglc,
705 jlong pSrcOps, jlong pDstOps, jint dsttype,
706 jint srcx, jint srcy, jint dstx, jint dsty,
707 jint width, jint height)
708 {
709 OGLSDOps *srcOps = (OGLSDOps *)jlong_to_ptr(pSrcOps);
710 SurfaceDataOps *dstOps = (SurfaceDataOps *)jlong_to_ptr(pDstOps);
711 SurfaceDataRasInfo srcInfo, dstInfo;
712 OGLPixelFormat pf = PixelFormats[dsttype];
713
714 J2dTraceLn(J2D_TRACE_INFO, "OGLBlitLoops_SurfaceToSwBlit");
715
716 if (width <= 0 || height <= 0) {
717 J2dTraceLn(J2D_TRACE_WARNING,
718 "OGLBlitLoops_SurfaceToSwBlit: dimensions are non-positive");
719 return;
741
742 SurfaceData_IntersectBoundsXYXY(&srcInfo.bounds,
743 0, 0, srcOps->width, srcOps->height);
744 SurfaceData_IntersectBlitBounds(&dstInfo.bounds, &srcInfo.bounds,
745 srcx - dstx, srcy - dsty);
746
747 if (srcInfo.bounds.x2 > srcInfo.bounds.x1 &&
748 srcInfo.bounds.y2 > srcInfo.bounds.y1)
749 {
750 dstOps->GetRasInfo(env, dstOps, &dstInfo);
751 if (dstInfo.rasBase) {
752 void *pDst = dstInfo.rasBase;
753
754 srcx = srcInfo.bounds.x1;
755 srcy = srcInfo.bounds.y1;
756 dstx = dstInfo.bounds.x1;
757 dsty = dstInfo.bounds.y1;
758 width = srcInfo.bounds.x2 - srcInfo.bounds.x1;
759 height = srcInfo.bounds.y2 - srcInfo.bounds.y1;
760
761 j2d_glPixelStorei(GL_PACK_SKIP_PIXELS, dstx);
762 j2d_glPixelStorei(GL_PACK_ROW_LENGTH,
763 dstInfo.scanStride / dstInfo.pixelStride);
764 j2d_glPixelStorei(GL_PACK_ALIGNMENT, pf.alignment);
765 #ifdef MACOSX
766 if (srcOps->isOpaque) {
767 // For some reason Apple's OpenGL implementation will
768 // read back zero values from the alpha channel of an
769 // opaque surface when using glReadPixels(), so here we
770 // force the resulting pixels to be fully opaque.
771 j2d_glPixelTransferf(GL_ALPHA_BIAS, 1.0);
772 }
773 #endif
774
775 J2dTraceLn4(J2D_TRACE_VERBOSE, " sx=%d sy=%d w=%d h=%d",
776 srcx, srcy, width, height);
777 J2dTraceLn2(J2D_TRACE_VERBOSE, " dx=%d dy=%d",
778 dstx, dsty);
779
780 // this accounts for lower-left origin of the source region
781 srcx = srcOps->xOffset + srcx;
782 srcy = srcOps->yOffset + srcOps->height - (srcy + 1);
783
784 // we must read one scanline at a time because there is no way
785 // to read starting at the top-left corner of the source region
786 while (height > 0) {
787 j2d_glPixelStorei(GL_PACK_SKIP_ROWS, dsty);
788 j2d_glReadPixels(srcx, srcy, width, 1,
789 pf.format, pf.type, pDst);
790 srcy--;
791 dsty++;
792 height--;
793 }
794
795 #ifdef MACOSX
796 if (srcOps->isOpaque) {
797 j2d_glPixelTransferf(GL_ALPHA_BIAS, 0.0);
798 }
799 #endif
800
801 j2d_glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
802 j2d_glPixelStorei(GL_PACK_SKIP_ROWS, 0);
803 j2d_glPixelStorei(GL_PACK_ROW_LENGTH, 0);
804 j2d_glPixelStorei(GL_PACK_ALIGNMENT, 4);
805 }
806 SurfaceData_InvokeRelease(env, dstOps, &dstInfo);
807 }
808 SurfaceData_InvokeUnlock(env, dstOps, &dstInfo);
809 }
810
811 void
812 OGLBlitLoops_CopyArea(JNIEnv *env,
813 OGLContext *oglc, OGLSDOps *dstOps,
814 jint x, jint y, jint width, jint height,
815 jint dx, jint dy)
816 {
817 SurfaceDataBounds srcBounds, dstBounds;
818
819 J2dTraceLn(J2D_TRACE_INFO, "OGLBlitLoops_CopyArea");
820
821 RETURN_IF_NULL(oglc);
822 RETURN_IF_NULL(dstOps);
|
1 /*
2 * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 #ifndef HEADLESS
27
28 #include <jni.h>
29 #include <jlong.h>
30
31 #include "SurfaceData.h"
32 #include "OGLBlitLoops.h"
33 #include "OGLRenderQueue.h"
34 #include "OGLSurfaceData.h"
35 #include "GraphicsPrimitiveMgr.h"
36
37 #include <stdlib.h> // malloc
38 #include <string.h> // memcpy
39 #include "IntArgbPre.h"
40
41 extern OGLPixelFormat PixelFormats[];
42
43 /**
44 * Inner loop used for copying a source OpenGL "Surface" (window, pbuffer,
45 * etc.) to a destination OpenGL "Surface". Note that the same surface can
46 * be used as both the source and destination, as is the case in a copyArea()
47 * operation. This method is invoked from OGLBlitLoops_IsoBlit() as well as
48 * OGLBlitLoops_CopyArea().
49 *
50 * The standard glCopyPixels() mechanism is used to copy the source region
51 * into the destination region. If the regions have different dimensions,
52 * the source will be scaled into the destination as appropriate (only
53 * nearest neighbor filtering will be applied for simple scale operations).
54 */
55 static void
56 OGLBlitSurfaceToSurface(OGLContext *oglc, OGLSDOps *srcOps, OGLSDOps *dstOps,
57 jint sx1, jint sy1, jint sx2, jint sy2,
58 jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2)
59 {
60 GLfloat scalex, scaley;
322 GLvoid *pSrc = PtrCoord(srcInfo->rasBase,
323 sx, srcInfo->pixelStride,
324 sy, srcInfo->scanStride);
325
326 while (tmph > 0) {
327 j2d_glTexSubImage2D(GL_TEXTURE_2D, 0,
328 0, sh - tmph, sw, 1,
329 pf->format, pf->type,
330 pSrc);
331 pSrc = PtrAddBytes(pSrc, srcInfo->scanStride);
332 tmph--;
333 }
334 } else {
335 j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, sx);
336 j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, sy);
337
338 j2d_glTexSubImage2D(GL_TEXTURE_2D, 0,
339 0, 0, sw, sh,
340 pf->format, pf->type,
341 srcInfo->rasBase);
342
343 j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
344 j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
345 }
346
347 // the texture image is "right side up", so we align the
348 // upper-left texture corner with the upper-left quad corner
349 j2d_glBegin(GL_QUADS);
350 j2d_glTexCoord2d(tx1, ty1); j2d_glVertex2d(dx, dy);
351 j2d_glTexCoord2d(tx2, ty1); j2d_glVertex2d(dx + dw, dy);
352 j2d_glTexCoord2d(tx2, ty2); j2d_glVertex2d(dx + dw, dy + dh);
353 j2d_glTexCoord2d(tx1, ty2); j2d_glVertex2d(dx, dy + dh);
354 j2d_glEnd();
355 } else {
356 // this accounts for lower-left origin of the source region
357 jint newsx = srcOps->xOffset + sx;
358 jint newsy = srcOps->yOffset + srcOps->height - (sy + sh);
359 j2d_glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
360 0, 0, newsx, newsy, sw, sh);
361
362 // the texture image is "upside down" after the last step, so
363 // we align the bottom-left texture corner with the upper-left
364 // quad corner (and vice versa) to effectively flip the
687 sx1, sy1, sx2, sy2,
688 dx1, dy1, dx2, dy2);
689 } else {
690 OGLBlitSwToSurface(oglc, &srcInfo, &pf,
691 sx1, sy1, sx2, sy2,
692 dx1, dy1, dx2, dy2);
693 }
694 }
695
696 j2d_glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
697 j2d_glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
698 j2d_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
699 j2d_glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
700 }
701 SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
702 }
703 SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
704 }
705
706 /**
707 * This method makes vertical flip of the provided area of Surface and convert
708 * pixel's data from argbPre to argb format if requested.
709 */
710 void flip(void *pDst, juint w, juint h, jint scanStride, jboolean convert) {
711 const size_t clippedStride = 4 * w;
712 void *tempRow = (h > 1 && !convert) ? malloc(clippedStride) : NULL;
713 juint i = 0;
714 juint step = 0;
715 // vertical flip and convert argbpre to argb if necessary
716 for (; i < h / 2; ++i) {
717 juint *r1 = PtrAddBytes(pDst, (i * scanStride));
718 juint *r2 = PtrAddBytes(pDst, (h - i - 1) * scanStride);
719 if (tempRow) {
720 // fast path
721 memcpy(tempRow, r1, clippedStride);
722 memcpy(r1, r2, clippedStride);
723 memcpy(r2, tempRow, clippedStride);
724 } else {
725 // slow path
726 for (step = 0; step < w; ++step) {
727 juint tmp = r1[step];
728 if (convert) {
729 LoadIntArgbPreTo1IntArgb(r2, 0, step, r1[step]);
730 LoadIntArgbPreTo1IntArgb(&tmp, 0, 0, r2[step]);
731 } else {
732 r1[step] = r2[step];
733 r2[step] = tmp;
734 }
735 }
736 }
737 }
738 // convert the middle line if necessary
739 if (convert && h % 2) {
740 juint *r1 = PtrAddBytes(pDst, (i * scanStride));
741 for (step = 0; step < w; ++step) {
742 LoadIntArgbPreTo1IntArgb(r1, 0, step, r1[step]);
743 }
744 }
745 if (tempRow) {
746 free(tempRow);
747 }
748 }
749
750 /**
751 * Specialized blit method for copying a native OpenGL "Surface" (pbuffer,
752 * window, etc.) to a system memory ("Sw") surface.
753 */
754 void
755 OGLBlitLoops_SurfaceToSwBlit(JNIEnv *env, OGLContext *oglc,
756 jlong pSrcOps, jlong pDstOps, jint dsttype,
757 jint srcx, jint srcy, jint dstx, jint dsty,
758 jint width, jint height)
759 {
760 OGLSDOps *srcOps = (OGLSDOps *)jlong_to_ptr(pSrcOps);
761 SurfaceDataOps *dstOps = (SurfaceDataOps *)jlong_to_ptr(pDstOps);
762 SurfaceDataRasInfo srcInfo, dstInfo;
763 OGLPixelFormat pf = PixelFormats[dsttype];
764
765 J2dTraceLn(J2D_TRACE_INFO, "OGLBlitLoops_SurfaceToSwBlit");
766
767 if (width <= 0 || height <= 0) {
768 J2dTraceLn(J2D_TRACE_WARNING,
769 "OGLBlitLoops_SurfaceToSwBlit: dimensions are non-positive");
770 return;
792
793 SurfaceData_IntersectBoundsXYXY(&srcInfo.bounds,
794 0, 0, srcOps->width, srcOps->height);
795 SurfaceData_IntersectBlitBounds(&dstInfo.bounds, &srcInfo.bounds,
796 srcx - dstx, srcy - dsty);
797
798 if (srcInfo.bounds.x2 > srcInfo.bounds.x1 &&
799 srcInfo.bounds.y2 > srcInfo.bounds.y1)
800 {
801 dstOps->GetRasInfo(env, dstOps, &dstInfo);
802 if (dstInfo.rasBase) {
803 void *pDst = dstInfo.rasBase;
804
805 srcx = srcInfo.bounds.x1;
806 srcy = srcInfo.bounds.y1;
807 dstx = dstInfo.bounds.x1;
808 dsty = dstInfo.bounds.y1;
809 width = srcInfo.bounds.x2 - srcInfo.bounds.x1;
810 height = srcInfo.bounds.y2 - srcInfo.bounds.y1;
811
812 pDst = PtrAddBytes(pDst, dstx * dstInfo.pixelStride);
813 pDst = PtrAddBytes(pDst, dsty * dstInfo.scanStride);
814
815 j2d_glPixelStorei(GL_PACK_ROW_LENGTH,
816 dstInfo.scanStride / dstInfo.pixelStride);
817 j2d_glPixelStorei(GL_PACK_ALIGNMENT, pf.alignment);
818 #ifdef MACOSX
819 if (srcOps->isOpaque) {
820 // For some reason Apple's OpenGL implementation will
821 // read back zero values from the alpha channel of an
822 // opaque surface when using glReadPixels(), so here we
823 // force the resulting pixels to be fully opaque.
824 j2d_glPixelTransferf(GL_ALPHA_BIAS, 1.0);
825 }
826 #endif
827
828 J2dTraceLn4(J2D_TRACE_VERBOSE, " sx=%d sy=%d w=%d h=%d",
829 srcx, srcy, width, height);
830 J2dTraceLn2(J2D_TRACE_VERBOSE, " dx=%d dy=%d",
831 dstx, dsty);
832
833 // this accounts for lower-left origin of the source region
834 srcx = srcOps->xOffset + srcx;
835 srcy = srcOps->yOffset + srcOps->height - srcy - height;
836
837 // Note that glReadPixels() is extremely slow!
838 // So we call it only once and flip the image using memcpy.
839 j2d_glReadPixels(srcx, srcy, width, height,
840 pf.format, pf.type, pDst);
841 // It was checked above that width and height are positive.
842 flip(pDst, (juint) width, (juint) height, dstInfo.scanStride,
843 !pf.isPremult && !srcOps->isOpaque);
844 #ifdef MACOSX
845 if (srcOps->isOpaque) {
846 j2d_glPixelTransferf(GL_ALPHA_BIAS, 0.0);
847 }
848 #endif
849 j2d_glPixelStorei(GL_PACK_ROW_LENGTH, 0);
850 j2d_glPixelStorei(GL_PACK_ALIGNMENT, 4);
851 }
852 SurfaceData_InvokeRelease(env, dstOps, &dstInfo);
853 }
854 SurfaceData_InvokeUnlock(env, dstOps, &dstInfo);
855 }
856
857 void
858 OGLBlitLoops_CopyArea(JNIEnv *env,
859 OGLContext *oglc, OGLSDOps *dstOps,
860 jint x, jint y, jint width, jint height,
861 jint dx, jint dy)
862 {
863 SurfaceDataBounds srcBounds, dstBounds;
864
865 J2dTraceLn(J2D_TRACE_INFO, "OGLBlitLoops_CopyArea");
866
867 RETURN_IF_NULL(oglc);
868 RETURN_IF_NULL(dstOps);
|