Here's a few more snippets of information I've managed to uncover on android renderscript:
* Compiled on the device
* Uses acc compiler
* No architectural support issues.
* No external libraries
* You cannot #include
* No allocation allowed
* Safe predictable
I admit some of these statements don't give too much away, but there's not too much else to go on at the moment. It does seem to point to a language that is compiled and is C like, but maybe with not all the power of C as allocations are not allowed.
Trying to shed some more light on things I had another look in the source code and found a few simple example Android applications using renderscript. One of these simple example applications was called Fountain , it seemed to be one of the simplest applications so i thought it would be a good place to start.
The Android Fountain renderscript example
What does this application do? Well I'm not totally sure because i haven't run it myself, and to be honest there are not many comments in the code, so it really is a case of read the code and work it out. My best guess is that it produces a Fountain like animation that randomly animates points on a screen generally moving up and outwards in a fountain like way. These animations start when a users touches the screen and originate from that point. This is my best guess at the moment from what I can make out in the code example.
OK so what does the code look like?. First lets have a look at the files and how they are layed out, the structure is :
* Android.mk
* AndroidManifest.xml
* res
o drawable
+ gadgets_clock_mp3.png
o raw
+ fountain.c
* src
o com
+ android
# fountain
# Fountain.java
# FountainRS.java
# FountainView.java
Most of what we see here is a standard looking Android application. We have the basic android files such as the AndroidManifest file. Then we have our src directory that contains our android application source files,also we have the res directory, not unusual as it contains the drawable and raw directories, but as you can see the raw directory contains one very interesting and rather unusual file, the fountain.c file. This, it seems, is where the renderscript code resides, and the name does indeed suggest that it is C code file. So lets have a look at what is contained in this file:
01.// Fountain test script
02.#pragma version(1)
03.
04.int newPart = 0;
05.
06.int main(int launchID) {
07. int ct;
08. int count = Control->count;
09. int rate = Control->rate;
10. float height = getHeight();
11. struct point_s * p = (struct point_s *)point;
12.
13. if (rate) {
14. float rMax = ((float)rate) * 0.005f;
15. int x = Control->x;
16. int y = Control->y;
17. char r = Control->r * 255.f;
18. char g = Control->g * 255.f;
19. char b = Control->b * 255.f;
20. struct point_s * np = &p[newPart];
21.
22. while (rate--) {
23. vec2Rand((float *)np, rMax);
24. np->x = x;
25. np->y = y;
26. np->r = r;
27. np->g = g;
28. np->b = b;
29. np->a = 0xf0;
30. newPart++;
31. np++;
32. if (newPart >= count) {
33. newPart = 0;
34. np = &p[newPart];
35. }
36. }
37. }
38.
39. for (ct=0; ct < count; ct++) {
40. float dy = p->dy + 0.15f;
41. float posy = p->y + dy;
42. if ((posy > height) && (dy > 0)) {
43. dy *= -0.3f;
44. }
45. p->dy = dy;
46. p->x += p->dx;
47. p->y = posy;
48. p++;
49. }
50.
51. uploadToBufferObject(NAMED_PartBuffer);
52. drawSimpleMesh(NAMED_PartMesh);
53. return 1;
54.}
Yes,it is very C like. We have structs, pointers and chars. Starting at the top of the file. We have a Control structure or class that gives use a rate and a count as well as x,y and r,g,b values. Where does this Control structure get instantiated? I'll come back to this. Another structure that is also used in this code is point_s. This structure has a x and y coordinates, r,g,b values, which are likely to be Red, blue green, and an "a" value which is the alpha value. Without more information I cannot be sure exactly what is happening in this code,but I think that generally an array of points is given and then array of new points is generated, to allow some kind of animation.
Looking at the src code directory we have three .java files. Fountain.java,FountainView.java and FountainRS.java. Fountain.java is just the basic Android activity class that has an onCreate method that sets the contentView to an instance of FountainView. The Code for the FountainView.java file looks like this:
01./*
02. * Copyright (C) 2008 The Android Open Source Project
03. *
04. * Licensed under the Apache License, Version 2.0 (the "License");
05. * you may not use this file except in compliance with the License.
06. * You may obtain a copy of the License at
07. *
08. * http://www.apache.org/licenses/LICENSE-2.0
09. *
10. * Unless required by applicable law or agreed to in writing, software
11. * distributed under the License is distributed on an "AS IS" BASIS,
12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13. * See the License for the specific language governing permissions and
14. * limitations under the License.
15. */
16.
17.package com.android.fountain;
18.
19.import java.io.Writer;
20.import java.util.ArrayList;
21.import java.util.concurrent.Semaphore;
22.
23.import android.renderscript.RSSurfaceView;
24.import android.renderscript.RenderScript;
25.
26.import android.content.Context;
27.import android.content.res.Resources;
28.import android.graphics.Bitmap;
29.import android.graphics.drawable.BitmapDrawable;
30.import android.graphics.drawable.Drawable;
31.import android.os.Handler;
32.import android.os.Message;
33.import android.util.AttributeSet;
34.import android.util.Log;
35.import android.view.Surface;
36.import android.view.SurfaceHolder;
37.import android.view.SurfaceView;
38.import android.view.KeyEvent;
39.import android.view.MotionEvent;
40.
41.public class FountainView extends RSSurfaceView {
42.
43. public FountainView(Context context) {
44. super(context);
45. //setFocusable(true);
46. }
47.
48. private RenderScript mRS;
49. private FountainRS mRender;
50.
51. private void destroyRS() {
52. if(mRS != null) {
53. mRS = null;
54. destroyRenderScript();
55. }
56. java.lang.System.gc();
57. }
58.
59. public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
60. super.surfaceChanged(holder, format, w, h);
61. destroyRS();
62. mRS = createRenderScript(false, true);
63. mRender = new FountainRS();
64. mRender.init(mRS, getResources(), w, h);
65. }
66.
67. public void surfaceDestroyed(SurfaceHolder holder) {
68. // Surface will be destroyed when we return
69. destroyRS();
70. }
71.
72.
73.
74. @Override
75. public boolean onTouchEvent(MotionEvent ev)
76. {
77. int act = ev.getAction();
78. if (act == ev.ACTION_UP) {
79. mRender.newTouchPosition(0, 0, 0);
80. return false;
81. }
82. float rate = (ev.getPressure() * 50.f);
83. rate *= rate;
84. if(rate > 2000.f) {
85. rate = 2000.f;
86. }
87. mRender.newTouchPosition((int)ev.getX(), (int)ev.getY(), (int)rate);
88. return true;
89. }
90.}
The FountainView class is an Android View. As you can see from the code,FountainView extends a new type of Android view RSSufraceView. It also has references to a new RenderScript class and our defined FountainRS class. When creating a new surface in the surfacedChanged method a new RenderScript class and a new FountainRS class are created. We also call the init method on the FountainRS class and pass in several arguments,including a reference to the RenderScript object. So lets have a look at the FountainRS.java file:
001./*
002. * Copyright (C) 2008 The Android Open Source Project
003. *
004. * Licensed under the Apache License, Version 2.0 (the "License");
005. * you may not use this file except in compliance with the License.
006. * You may obtain a copy of the License at
007. *
008. * http://www.apache.org/licenses/LICENSE-2.0
009. *
010. * Unless required by applicable law or agreed to in writing, software
011. * distributed under the License is distributed on an "AS IS" BASIS,
012. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013. * See the License for the specific language governing permissions and
014. * limitations under the License.
015. */
016.
017.package com.android.fountain;
018.
019.import android.content.res.Resources;
020.import android.renderscript.*;
021.import android.util.Log;
022.
023.
024.public class FountainRS {
025. public static final int PART_COUNT = 20000;
026.
027. static class SomeData {
028. public int x;
029. public int y;
030. public int rate;
031. public int count;
032. public float r;
033. public float g;
034. public float b;
035. }
036.
037. public FountainRS() {
038. }
039.
040. public void init(RenderScript rs, Resources res, int width, int height) {
041. mRS = rs;
042. mRes = res;
043. initRS();
044. }
045.
046. public void newTouchPosition(int x, int y, int rate) {
047. if (mSD.rate == 0) {
048. mSD.r = ((x & 0x1) != 0) ? 0.f : 1.f;
049. mSD.g = ((x & 0x2) != 0) ? 0.f : 1.f;
050. mSD.b = ((x & 0x4) != 0) ? 0.f : 1.f;
051. if ((mSD.r + mSD.g + mSD.b) < 0.9f) {
052. mSD.r = 0.8f;
053. mSD.g = 0.5f;
054. mSD.b = 1.f;
055. }
056. }
057. mSD.rate = rate;
058. mSD.x = x;
059. mSD.y = y;
060. mIntAlloc.data(mSD);
061. }
062.
063.
064. /////////////////////////////////////////
065.
066. private Resources mRes;
067.
068. private RenderScript mRS;
069. private Allocation mIntAlloc;
070. private SimpleMesh mSM;
071. private SomeData mSD;
072. private Type mSDType;
073.
074. private void initRS() {
075. mSD = new SomeData();
076. mSDType = Type.createFromClass(mRS, SomeData.class, 1, "SomeData");
077. mIntAlloc = Allocation.createTyped(mRS, mSDType);
078. mSD.count = PART_COUNT;
079. mIntAlloc.data(mSD);
080.
081. Element.Builder eb = new Element.Builder(mRS);
082. eb.addFloat(Element.DataKind.USER, "dx");
083. eb.addFloat(Element.DataKind.USER, "dy");
084. eb.addFloatXY("");
085. eb.addUNorm8RGBA("");
086. Element primElement = eb.create();
087.
088.
089. SimpleMesh.Builder smb = new SimpleMesh.Builder(mRS);
090. int vtxSlot = smb.addVertexType(primElement, PART_COUNT);
091. smb.setPrimitive(Primitive.POINT);
092. mSM = smb.create();
093. mSM.setName(" PartMesh");
094.
095. Allocation partAlloc = mSM.createVertexAllocation(vtxSlot);
096. partAlloc.setName(" PartBuffer");
097. mSM.bindVertexAllocation(partAlloc, 0);
098.
099. // All setup of named objects should be done by this point
100. // because we are about to compile the script.
101. ScriptC.Builder sb = new ScriptC.Builder(mRS);
102. sb.setScript(mRes, R.raw.fountain);
103. sb.setRoot(true);
104. sb.setType(mSDType, "Control", 0);
105. sb.setType(mSM.getVertexType(0), "point", 1);
106. Script script = sb.create();
107. script.setClearColor(0.0f, 0.0f, 0.0f, 1.0f);
108.
109. script.bindAllocation(mIntAlloc, 0);
110. script.bindAllocation(partAlloc, 1);
111. mRS.contextBindRootScript(script);
112. }
113.
114.}
I'm not going to try and go through every detail of this code, but it seems that the interesting areas are in the initRS function. Here we have element builders, Simple Mesh builders and last but not least a script builder. Here we get a script builder instance, set the script to the fountain.c file. Set up some types such as Control and point (remember,these were used in the fountain.c file) and then create the script.
So there we have it, this is a quick peek into how Renderscript might be used. There are still a lot of unanswered questions yet, and there is still a lot more to learn about how renderscript will, and can be use,but i hope these few code snippets will at least give people a starting point. As usual, if anyone else out there has any interesting insights or comments I'd be really interested to hear them.
posted at 15:09:8 | (54) View | (0) TrackBack pings | (0) Comments
工程res/raw/*.c里用的方法,发现在rsScriptC_Lib.cpp里有实现且是用标准opengl es函数实现。
工程java文件很多接口调到了rsgApi.cpp里,在里面被封装成了一条命令并加进先入先出命令队列执行。
libacc : Android 2.0 內建的輕量級 C Compiler Thursday, March 04, 2010
By 0xlab
Android 2.0 (Eclair) 原始程式碼已於一個月前釋出,在目錄 system/core 下有個 libacc 的子項目,這是開發者修改自 Fabrice Bellard 的大作 OTCC (Obfuscated Tiny C Compiler),以 C++ 與 Android 的執行時期函式庫重寫。libacc 的功能是提供給 Android 2.0 的 RenderScript 一個 C-like 語法的描述,如此一來,開發者可撰寫高效能的視覺效果與動畫,不過這部份並未完成,詳情可參考 "Android RenderScript,more info" 一文。
關於 libacc 的整合部份,可參考 frameworks/base/libs/rs 目錄下的兩個檔案:
* rsScriptC.cpp
* rsScriptC_Lib.cpp
筆者準備了一份可單獨執行於 GNU/Linux 環境的套件:"libacc.tar.bz2",除去 Android 的相依性並補上 Makefile,測試方式如下:
libacc$ make
g++ -I./include -DHAVE_PTHREADS -c acc.cpp
gcc -I./include -DHAVE_PTHREADS -c hashmap.c
gcc -I./include -DHAVE_PTHREADS -c logd_write.c
g++ -I./include -DHAVE_PTHREADS -c tests/main.cpp
g++ -I./include -DHAVE_PTHREADS -c tests/runtimeTest.cpp
g++ -o main /
acc.o /
hashmap.o /
logd_write.o /
main.o /
-ldl
g++ -o runtimeTest /
acc.o /
hashmap.o /
logd_write.o /
runtimeTest.o /
-ldl
libacc 的 Code generator 支援以下硬體架構:
* x86 / IA32
* x86_64
* ARMv5
以 IA32 的環境為例,可透過測試程式來驗證 libacc: (參數 -R 表示作執行的動作)
libacc$ ./main -R tests/data/hello.c
Executing compiled code:
Hello, world
result: 0
其中 tests/data/hello.c 的內容為:
libacc$ cat tests/data/hello.c
int main() {
printf("Hello, world/n");
return 0;
}
若平台是 ARM 的話,還可以支援反組譯輸出,libacc 是 RenderScript 背後很重要的基礎建設,允許動態編譯AndroidGraphics 的 RenderScript,輸出成機械碼並執行。參考檔案 tests/runtimeTest.cpp可得知RenderScript 的寫法,整個 libacc 可內嵌於程式中,比方說:
const char* text = "void op_int(int a);/n"
"void op_float12(float a, float b, float c, float d,/n"
" float e, float f, float g, float h,/n"
" float i, float j, float k, float l);/n"
"void script() {/n"
" globalVar += 3;/n"
" op_int(123);/n"
" op_float12(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0);/n"
"}/n";
這個字串經過 libacc 的函式呼叫後,可得到以下的編譯與執行結果:
libacc$ ./runtimeTest
Executing script:
op_int(123)
op_float12(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
After script globalVar = 20
目錄 tests 還包含可在 Android 環境執行的自動測試 Python script。
script执行过程: 1、create script mRS = new RenderScript(false, false); ->mContext = nContextCreate(mDev, 0, useDepth); ->rsContextCreate ->new Context(dev, useDepth); ->pthread_create(&mThreadId, &threadAttr, threadProc, this); ->Context::threadProc(void *vrsc) ->mDraw |= rsc->mIO.playCoreCommands(rsc, !mDraw); ->gPlaybackFuncs[cmdID](con, data); ->RsPlaybackFunc gPlaybackFuncs[] ->rsp_ScriptCCreate ->(intptr_t)rsi_ScriptCCreate(con); ->ss->runCompiler(rsc, s); ->s->mAccScript = accCreateScript(); 2、setDataSource sb.setScript(getResources(), R.raw.threshold); ->mProgram = buf;mProgramLength = currentPos; sb.create(); ->internalCreate(this); ->b.mRS.nScriptCSetScript(b.mProgram, 0, b.mProgramLength); ->rsScriptCSetText(con, (const char *)script_ptr, length); ->io->mToCore.commitSync(RS_CMD_ID_ScriptCSetText, size); ->LocklessCommandFifo::commitSync ->LocklessCommandFifo::Signal::set() ->pthread_cond_signal(&mCondition); ->__futex_wake ->asm volatile ( "int $0x80;" : "=a" (ret) : "0" (FUTEX_SYSCALL), "b" (ftx), "c" (FUTEX_WAKE), "d" (count) ); 3、compile & parser accCompileScript(script); accGetPragmas(script, NULL, numPragmaStrings, strings); 下面的不一定是compile & parser script.bindAllocation(mParamsAllocation, 0); ->mRS.nScriptBindAllocation(mID, va.mID, slot); ->rsScriptBindAllocation(con, (RsScript)script, (RsAllocation)alloc, slot); ->io->mToCore.commit(RS_CMD_ID_ScriptBindAllocation, size); 4、run accGetScriptLabel(script, "script", (ACCvoid**) & scriptPointer); run(scriptPointer); 下面的并不是run. int id = b.mRS.nScriptCCreate(); ->nScriptCCreate ->return (jint)rsScriptCCreate(con); ->io->mToCore.commitSync(RS_CMD_ID_ScriptCCreate, size); 到了io->mToCore.commit,把上面的数据会封装成命令送到命令队列,然后命令是怎样执行的呢? |