Sample Code

From ShWiki

Here are some examples of programs which use Sh. Feel free to suggest additions to this page if you want.

Contents

Simple stream program

Here is a minimal stream program showing how to create storage for program inputs and outputs.

#include <sh/sh.hpp>
#include <iostream>

using namespace std;
using namespace SH;

int main()
{
  shInit();

  ShProgram prg = SH_BEGIN_PROGRAM("gpu:stream") {
    ShInputAttrib3f a;
    ShOutputAttrib3f b;
    b = a + ShAttrib3f(42.0, 42.0, 42.0);
  } SH_END;

  float data[] = { 1.0, 0.5, -0.5 };
  ShHostMemoryPtr mem_in = new ShHostMemory(sizeof(float) * 3, data, SH_FLOAT);
  ShChannel<ShAttrib3f> in(mem_in, 1);

  float outdata[3];
  ShHostMemoryPtr mem_out = new ShHostMemory(sizeof(float) * 3, outdata, SH_FLOAT);
  ShChannel<ShAttrib3f> out(mem_out, 1);

  out = prg << in;
  
  mem_out->hostStorage()->sync();
  float* results = static_cast<float*>(mem_out->hostStorage()->data());
  cout << "out = (" << results[0] << ", " << results[1] << ", "
       << results[2] << ")" << endl;
}

It should simply output the following:

out = (43, 42.5, 41.5)

Comments/Hints/Tips

FIX: Try to insert these lines right after main if you encountered some GL runtime error(test on Windows/Visual C++ 7.1). It seems that it went down without initializing OpenGL...hmm, I have no idea, but if anyone could tell me, thanks in advance.

  glutInitDisplayMode(GLUT_RGBA);
  glutInitWindowSize(512, 512);
  glutCreateWindow("Sh Sample Code");
  SH::shSetBackend("glsl");
Simply setting the backend tends to work right now, but you should really call "shInit" before using Sh to initialize the internal context (Note: it *may* be necessary to create a window and initialize a GL context before calling shInit... I don't remember). It's probably also a good idea to subsequently call "shUseBackend(...)" for each backend that you want available. --atlaurit 16:16, 30 January 2006 (EST)



Could someone provide the gcc - command (link to which libraries etc.) for total beginners like me who just want to verify the correct installation of Sh?

Sure can ... assuming you have both glut (http://freeglut.sourceforge.net/) and sh libraries installed you should be able to run
g++ source.cpp -o simpleStream -lsh -lglut
The code -does- compile without error if you do not include the glut library ... though it fails at runtime with something similar to
symbol lookup error: /usr/local/lib/sh/libshgl.so.0: undefined symbol: glXGetCurrentDisplay

--Rob 12:04, 23 January 2006 (EST)


Tried running the sample code and I got the following error: 'could not find a backend that supports the 'gpu:stream' target.'. Does anyone have any idea what this means?

--Rus 11:51, 13 April, 2006 (PT)

On Windows, Sh looks for backends in the PATH and in the current directory. So you may want to try putting the Sh installation directory into the PATH or try setting your Visual Studio "working directory" differently. --Francois 12:32, 24 April 2006 (EDT)

Using the connect operator

The connect operator allows one to "chain" shaders together. This is described in the book on page 190. Here's an example extending the stream program described above.

Here's the new shader which does the actual doubling:

 ShProgram double_prg = SH_BEGIN_PROGRAM("gpu:stream") {
   ShInputAttrib3f a;
   ShOutputAttrib3f b;
   b = 2 * a;
 } SH_END;

and here's how it can be chained to the previous one:

 out = double_prg << prg << in;

Making this change to the sample stream program will now make it return the following:

 out = (86, 85, 83)

Note that the doubling happens after the original shader but that it is positioned to the left of prg.

Using strides and offsets

Note that this feature has not been implemented in the 0.8 branch, and most likely will not be. To use it you must currently check out the Sh trunk.

You can use strides and offsets to perform computation on a specific subset of the stream. For instance, suppose you have a trivial stream program that simply assigns the input to the output

 Program prg = SH_BEGIN_PROGRAM("gpu:stream") {
   InputAttrib1f a;
   OutputAttrib1f b;
   b = a;
 } SH_END;

You setup your input and output streams as follows

 float in_data[] = { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
 HostMemoryPtr in_mem = new HostMemory(sizeof(float) * 10, in_data, SH_FLOAT);
 Channel<Attrib1f> in(in_mem, 10);
 
 float out_data[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
 HostMemoryPtr out_mem = new HostMemory(sizeof(float) * 10, out_data, SH_FLOAT); 
 Channel<Attrib1f> out(out_mem, 10);

You can now assign a portion of the input to a portion of the output. So for instance, the execution of

 out.count(3);
 out.offset(2);
 out.stride(3);
 in.count(3);
 in.offset(5);
 in.stride(2);
 
 out = prg << in;

will result in the output memory contents:

 out = (1, 2, 60, 4, 5, 80, 7, 8, 100, 10)

Discussing the examples in the libsh-(version)/examples directory

particle

This is an example on how to use streams with Sh.

When using libsh-0.8.0rc0, I noticed severe performance differences when changing between the 2 settings cpu:stream and gpu:stream in the main.cpp. The strange part was that the CPU was much faster than the GPU setting (well, it should be the other way round, otherwise, what would be the point? ;)

Is this simply a result of the unmature state of the stream-computing part or is it just the fault of my graphics card? Could anyone with a better card (nvidia 6800/7800) verify this? --Hmueller 03:46, 27 January 2006 (EST)

Talking to sdt on the IRC channel verified that it was due to inefficiencies in the current code --Hmueller 12:38, 27 January 2006 (EST)